pkcs11: ECHD and secret keys support from Douglas

This support were initially proposed by Douglas (https://github.com/dengert/OpenSC/commits/ecdh) and
then merged into SM branch (https://github.com/viktorTarasov/OpenSC-SM/tree/secure-messaging).
This commit is contained in:
Viktor Tarasov 2012-05-26 21:17:39 +02:00
parent 76b8ad8ad6
commit 9c5dbea883
8 changed files with 1147 additions and 256 deletions

View File

@ -413,6 +413,21 @@ struct sc_pkcs15_pubkey_info {
};
typedef struct sc_pkcs15_pubkey_info sc_pkcs15_pubkey_info_t;
struct sc_pkcs15_skey_info {
struct sc_pkcs15_id id;
unsigned int usage, access_flags;
int native, key_reference;
size_t value_len;
unsigned long key_type;
int algo_refs[SC_MAX_SUPPORTED_ALGORITHMS];
struct sc_path path; /* if on card */
struct sc_pkcs15_der data;
};
typedef struct sc_pkcs15_skey_info sc_pkcs15_skey_info_t;
#define sc_pkcs15_skey sc_pkcs15_data
#define sc_pkcs15_skey_t sc_pkcs15_data_t
#define SC_PKCS15_TYPE_CLASS_MASK 0xF00
#define SC_PKCS15_TYPE_PRKEY 0x100
@ -427,6 +442,12 @@ typedef struct sc_pkcs15_pubkey_info sc_pkcs15_pubkey_info_t;
#define SC_PKCS15_TYPE_PUBKEY_GOSTR3410 0x203
#define SC_PKCS15_TYPE_PUBKEY_EC 0x204
#define SC_PKCS15_TYPE_SKEY 0x300
#define SC_PKCS15_TYPE_SKEY_GENERIC 0x301
#define SC_PKCS15_TYPE_SKEY_DES 0x302
#define SC_PKCS15_TYPE_SKEY_2DES 0x303
#define SC_PKCS15_TYPE_SKEY_3DES 0x304
#define SC_PKCS15_TYPE_CERT 0x400
#define SC_PKCS15_TYPE_CERT_X509 0x401
#define SC_PKCS15_TYPE_CERT_SPKI 0x402

View File

@ -10,7 +10,7 @@ OBJECTS = pkcs11-global.obj pkcs11-session.obj pkcs11-object.obj misc.obj slot
OBJECTS3 = pkcs11-spy.obj pkcs11-display.obj \
$(TOPDIR)\win32\versioninfo.res
all: $(TOPDIR)\win32\versioninfo.res $(TARGET0) $(TARGET1) $(TARGET3)
all: $(TOPDIR)\win32\versioninfo.res $(TARGET1) $(TARGET3)
!INCLUDE $(TOPDIR)\win32\Make.rules.mak

View File

@ -115,10 +115,22 @@ struct pkcs15_data_object {
#define data_p15obj base.p15_object
#define is_data(obj) (__p15_type(obj) == SC_PKCS15_TYPE_DATA_OBJECT)
struct pkcs15_skey_object {
struct pkcs15_any_object base;
struct sc_pkcs15_skey_info *info;
struct sc_pkcs15_skey *valueXXXX;
};
#define skey_flags base.base.flags
#define skey_p15obj base.p15_object
#define is_skey(obj) ((__p15_type(obj) & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_SKEY_OBJECT)
extern struct sc_pkcs11_object_ops pkcs15_cert_ops;
extern struct sc_pkcs11_object_ops pkcs15_prkey_ops;
extern struct sc_pkcs11_object_ops pkcs15_pubkey_ops;
extern struct sc_pkcs11_object_ops pkcs15_dobj_ops;
extern struct sc_pkcs11_object_ops pkcs15_skey_ops;
#define GOST_PARAMS_OID_SIZE 9
static const struct {
@ -150,9 +162,12 @@ static int lock_card(struct pkcs15_fw_data *);
static int unlock_card(struct pkcs15_fw_data *);
static int reselect_app_df(sc_pkcs15_card_t *p15card);
static CK_RV set_gost_params(struct sc_pkcs15init_keyarg_gost_params *,
struct sc_pkcs15init_keyarg_gost_params *,
CK_ATTRIBUTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG);
static CK_RV set_gost_params(struct sc_pkcs15init_keyarg_gost_params *,
struct sc_pkcs15init_keyarg_gost_params *,
CK_ATTRIBUTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG);
static CK_RV pkcs15_create_slot(struct sc_pkcs11_card *p11card, struct pkcs15_fw_data *fw_data,
struct sc_pkcs15_object *auth, struct sc_app_info *app,
struct sc_pkcs11_slot **out);
/* Returns forst available WF data or WF data corresponding to the given application */
static struct pkcs15_fw_data *
@ -621,7 +636,7 @@ __pkcs15_create_prkey_object(struct pkcs15_fw_data *fw_data,
static int
__pkcs15_create_data_object(struct pkcs15_fw_data *fw_data,
struct sc_pkcs15_object *object, struct pkcs15_any_object **data_object)
struct sc_pkcs15_object *object, struct pkcs15_any_object **data_object)
{
struct pkcs15_data_object *dobj = NULL;
int rv;
@ -641,6 +656,26 @@ __pkcs15_create_data_object(struct pkcs15_fw_data *fw_data,
}
static int
__pkcs15_create_secret_key_object(struct pkcs15_fw_data *fw_data,
struct sc_pkcs15_object *object, struct pkcs15_any_object **skey_object)
{
struct pkcs15_skey_object *skey = NULL;
int rv;
rv = __pkcs15_create_object(fw_data, (struct pkcs15_any_object **) &skey,
object, &pkcs15_skey_ops,
sizeof(struct pkcs15_skey_object));
if (rv >= 0) {
skey->info = (struct sc_pkcs15_skey_info *) object->data;
}
if (skey_object != NULL)
*skey_object = (struct pkcs15_any_object *) skey;
return 0;
}
static int
pkcs15_create_pkcs11_objects(struct pkcs15_fw_data *fw_data,
int p15_type, const char *name,
@ -1191,11 +1226,8 @@ pkcs15_create_tokens(struct sc_pkcs11_card *p11card, struct sc_app_info *app_inf
{
struct pkcs15_fw_data *fw_data = NULL, *ffda = NULL;
struct sc_pkcs15_object *auth_user_pin = NULL, *auth_sign_pin = NULL, *fauo = NULL;
// struct sc_pkcs15_object *auths[SC_PKCS15_MAX_PINS];
struct sc_pkcs11_slot *slot = NULL;
// int auth_count, found_auth_count = 0;
int i, rv, idx;
// unsigned int j;
sc_log(context, "create PKCS#15 tokens; fws:%p,%p,%p",
p11card->fws_data[0], p11card->fws_data[1], p11card->fws_data[2]);
@ -1564,18 +1596,19 @@ pkcs15_change_pin(struct sc_pkcs11_slot *slot,
int login_user = slot->login_user;
int rc;
if (!(pin_obj = slot_data_auth(slot->fw_data)))
pin_obj = slot_data_auth(slot->fw_data);
if (!pin_obj)
return CKR_USER_PIN_NOT_INITIALIZED;
if (!(auth_info = slot_data_auth_info(slot->fw_data)))
auth_info = slot_data_auth_info(slot->fw_data);
if (!auth_info)
return CKR_USER_PIN_NOT_INITIALIZED;
fw_data = (struct pkcs15_fw_data *) p11card->fws_data[slot->fw_data_idx];
if (!fw_data)
return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_SetPin");
sc_log(context, "Change '%s', reference %i; login type %i",
pin_obj->label, auth_info->attrs.pin.reference, login_user);
sc_log(context, "Change '%s' (ref:%i,type:%i)", pin_obj->label, auth_info->attrs.pin.reference, login_user);
if (p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
/* pPin should be NULL in case of a pin pad reader, but
* some apps (e.g. older Netscapes) don't know about it.
@ -1872,6 +1905,167 @@ out: return rv;
}
/* TODO Only Session secret key objects are supported for now
* Sesison objects have CKA_TOKEN=false
* This is used by the C_DeriveKey with ECDH to hold the
* key, and the calling application can then retrieve tha attributes as needed.
* TODO If a card can support secret key objects on the card, this
* code will need to be expanded.
*/
static CK_RV
pkcs15_create_secret_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile,
CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
CK_OBJECT_HANDLE_PTR phObject)
{
struct sc_pkcs11_card *p11card = slot->card;
struct pkcs15_fw_data *fw_data = NULL;
struct sc_pkcs15init_skeyargs args;
struct pkcs15_any_object *key_any_obj = NULL;
struct sc_pkcs15_object *key_obj = NULL;
struct sc_pkcs15_skey_info *skey_info;
CK_KEY_TYPE key_type;
CK_BBOOL _token = FALSE;
int rv;
char label[SC_PKCS15_MAX_LABEL_SIZE];
memset(&args, 0, sizeof(args));
fw_data = (struct pkcs15_fw_data *) p11card->fws_data[slot->fw_data_idx];
if (!fw_data)
return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_CreateObject");
#if 0
/* See if the "slot" is pin protected. If so, get the
* PIN id */
if ((pin = slot_data_auth_info(slot->fw_data)) != NULL)
args.auth_id = pin->auth_id;
#endif
/* Get the key type */
rv = attr_find(pTemplate, ulCount, CKA_KEY_TYPE, &key_type, NULL);
if (rv != CKR_OK)
return rv;
/* CKA_TOKEN defaults to false */
attr_find(pTemplate, ulCount, CKA_TOKEN, &_token, NULL);
switch (key_type) {
/* Only support GENERIC_SECRET for now */
case CKK_GENERIC_SECRET:
break;
default:
return CKR_ATTRIBUTE_VALUE_INVALID;
}
while (ulCount--) {
CK_ATTRIBUTE_PTR attr = pTemplate++;
switch (attr->type) {
/* Skip attrs we already know or don't care for */
case CKA_CLASS:
case CKA_KEY_TYPE:
case CKA_MODULUS_BITS:
case CKA_PRIVATE:
break;
case CKA_LABEL:
args.label = set_cka_label(attr, label);
break;
case CKA_ID:
args.id.len = sizeof(args.id.value);
rv = attr_extract(attr, args.id.value, &args.id.len);
if (rv != CKR_OK)
goto out;
break;
case CKA_VALUE_LEN:
attr_extract(attr, &args.value_len, NULL);
break;
case CKA_VALUE:
if (attr->pValue) {
args.data_value.value = calloc(1,attr->ulValueLen);
if (!args.data_value.value)
return CKR_HOST_MEMORY;
memcpy(args.data_value.value, attr->pValue, attr->ulValueLen);
args.data_value.len = attr->ulValueLen;
}
break;
case CKA_DECRYPT:
args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_DECRYPT);
break;
case CKA_ENCRYPT:
args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_ENCRYPT);
break;
case CKA_WRAP:
args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_WRAP);
break;
case CKA_UNWRAP:
args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_UNWRAP);
break;
default:
/* ignore unknown attrs, or flag error? */
continue;
}
}
/* If creating a PKCS#11 session object, i.e. one that is only in memory */
if (_token == FALSE) {
/* TODO Have 3 choices as to how to create the object.
* (1)create a sc_pkcs15init_store_secret_key routine like the others
* (2)use the sc_pkcs15emu_ routines
* (3)do it inline here (Will do this for now)
*/
key_obj = calloc(1, sizeof(sc_pkcs15_object_t));
if (key_obj == NULL) {
rv = CKR_HOST_MEMORY;
goto out;
}
key_obj->type = SC_PKCS15_TYPE_SKEY;
if (args.id.len)
memcpy(key_obj->label, args.id.value, args.id.len);
key_obj->flags = 2; /* TODO not sure what these mean */
skey_info = calloc(1, sizeof(sc_pkcs15_skey_info_t));
if (skey_info == NULL) {
rv = CKR_HOST_MEMORY;
goto out;
}
key_obj->data = skey_info;
skey_info->usage = args.usage;
skey_info->native = 0; /* card can not use this */
skey_info->access_flags = 0; /* looks like not needed */
skey_info->key_type = key_type; /* PKCS#11 CKK_* */
skey_info->data.value = args.data_value.value;
skey_info->data.len = args.data_value.len;
skey_info->value_len = args.value_len; /* callers prefered length */
}
else {
#if 1
rv = CKR_FUNCTION_NOT_SUPPORTED;
goto out;
#else
/* TODO add support for secret key on the card with something like this: */
rc = sc_pkcs15init_store_secret_key(fw_data->p15_card, profile, &args, &key_obj);
if (rc < 0) {
rv = sc_to_cryptoki_error(rc, "C_CreateObject");
goto out;
}
#endif
}
/* Create a new pkcs11 object for it */
__pkcs15_create_secret_key_object(fw_data, key_obj, &key_any_obj);
pkcs15_add_object(slot, key_any_obj, phObject);
rv = CKR_OK;
out:
return rv;
}
static CK_RV
pkcs15_create_public_key(struct sc_pkcs11_slot *slot,
struct sc_profile *profile,
@ -2146,6 +2340,7 @@ pkcs15_create_object(struct sc_pkcs11_slot *slot, CK_ATTRIBUTE_PTR pTemplate, CK
struct pkcs15_fw_data *fw_data = NULL;
struct sc_profile *profile = NULL;
CK_OBJECT_CLASS _class;
CK_BBOOL _token = FALSE;
int rv, rc;
fw_data = (struct pkcs15_fw_data *) p11card->fws_data[slot->fw_data_idx];
@ -2156,17 +2351,50 @@ pkcs15_create_object(struct sc_pkcs11_slot *slot, CK_ATTRIBUTE_PTR pTemplate, CK
if (rv != CKR_OK)
return rv;
rc = sc_lock(p11card->card);
if (rc < 0)
return sc_to_cryptoki_error(rc, "C_CreateObject");
/* Bind the profile */
rc = sc_pkcs15init_bind(p11card->card, "pkcs15", NULL, slot->app_info, &profile);
if (rc < 0) {
sc_unlock(p11card->card);
return sc_to_cryptoki_error(rc, "C_CreateObject");
rv = attr_find(pTemplate, ulCount, CKA_TOKEN, &_token, NULL);
if (rv == CKR_TEMPLATE_INCOMPLETE) {
/* TODO OpenSC has not checked CKA_TOKEN == TRUE, so only
* so only enforce for secret_key
*/
if (_class != CKO_SECRET_KEY)
_token = TRUE; /* default if not in template */
}
else if (rv != CKR_OK) {
return rv;
}
/* TODO The previous code does not check for CKA_TOKEN=TRUE
* PKCS#11 CreatObject examples always have it, but
* PKCS#11 says the default is false.
* for backward compatability, will default to TRUE
*/
/* Dont need profile id creating session only objects */
if (_token == TRUE) {
struct sc_aid *aid = NULL;
rc = sc_lock(p11card->card);
if (rc < 0)
return sc_to_cryptoki_error(rc, "C_CreateObject");
/* Bind the profile */
rc = sc_pkcs15init_bind(p11card->card, "pkcs15", NULL, slot->app_info, &profile);
if (rc < 0) {
sc_unlock(p11card->card);
return sc_to_cryptoki_error(rc, "C_CreateObject");
}
if (slot->app_info)
aid = &slot->app_info->aid;
rc = sc_pkcs15init_finalize_profile(p11card->card, profile, aid);
if (rc != CKR_OK) {
sc_log(context, "Cannot finalize profile: %i", rc);
sc_unlock(p11card->card);
return sc_to_cryptoki_error(rc, "C_CreateObject");
}
sc_pkcs15init_set_p15card(profile, fw_data->p15_card);
}
switch (_class) {
case CKO_PRIVATE_KEY:
rv = pkcs15_create_private_key(slot, profile, pTemplate, ulCount, phObject);
@ -2180,12 +2408,17 @@ pkcs15_create_object(struct sc_pkcs11_slot *slot, CK_ATTRIBUTE_PTR pTemplate, CK
case CKO_DATA:
rv = pkcs15_create_data(slot, profile, pTemplate, ulCount, phObject);
break;
case CKO_SECRET_KEY:
rv = pkcs15_create_secret_key(slot, profile, pTemplate, ulCount, phObject);
break;
default:
rv = CKR_FUNCTION_NOT_SUPPORTED;
}
sc_pkcs15init_unbind(profile);
sc_unlock(p11card->card);
if (_token == TRUE) {
sc_pkcs15init_unbind(profile);
sc_unlock(p11card->card);
}
return rv;
}
@ -2211,7 +2444,7 @@ get_X509_usage_privk(CK_ATTRIBUTE_PTR pTempl, CK_ULONG ulCount, unsigned long *x
if (typ == OPENSC_CKA_NON_REPUDIATION && *val)
*x509_usage |= SC_PKCS15INIT_X509_NON_REPUDIATION;
if (typ == CKA_VERIFY || typ == CKA_WRAP || typ == CKA_ENCRYPT) {
sc_log(context, "get_X509_usage_privk(): invalid typ = 0x%0x\n", typ);
sc_log(context, "get_X509_usage_privk(): invalid typ = 0x%0x", typ);
return CKR_ATTRIBUTE_TYPE_INVALID;
}
}
@ -2466,6 +2699,36 @@ kpgen_done:
#endif
static CK_RV
pkcs15_skey_destroy(struct sc_pkcs11_session *session, void *object)
{
struct pkcs15_any_object *any_obj = (struct pkcs15_any_object*) object;
struct sc_pkcs11_card *p11card = session->slot->card;
struct pkcs15_fw_data *fw_data = NULL;
int rv;
fw_data = (struct pkcs15_fw_data *) p11card->fws_data[session->slot->fw_data_idx];
if (!fw_data)
return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_GenerateKeyPair");
/* TODO assuming this is a session only object. */
rv = sc_lock(p11card->card);
if (rv < 0)
return sc_to_cryptoki_error(rv, "C_DestroyObject");
/* Oppose to pkcs15_add_object */
--any_obj->refcount; /* correct refcont */
list_delete(&session->slot->objects, any_obj);
/* Delete object in pkcs15 */
rv = __pkcs15_delete_object(fw_data, any_obj);
sc_unlock(p11card->card);
if (rv < 0)
return sc_to_cryptoki_error(rv, "C_DestroyObject");
return CKR_OK;
}
static CK_RV
pkcs15_any_destroy(struct sc_pkcs11_session *session, void *object)
{
@ -2862,23 +3125,36 @@ pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session,
sc_log(context, "use friend public key data %p", key);
}
else {
/* Try to find a certificate with the public key */
/* Try to find public key or certificate with the public key */
unsigned int i;
for (i = 0; i < fw_data->num_objects; i++) {
struct pkcs15_any_object *obj = fw_data->objects[i];
struct pkcs15_cert_object *cert;
if (!is_cert(obj))
continue;
if (is_cert(obj)) {
cert = (struct pkcs15_cert_object*) obj;
cert = (struct pkcs15_cert_object*) obj;
if (cert->cert_prvkey != prkey)
continue;
if (cert->cert_prvkey != prkey)
continue;
if (check_cert_data_read(fw_data, cert) == 0) {
key = cert->cert_pubkey->pub_data;
sc_log(context, "found friend certificate's public key %p", key);
}
}
else if (is_pubkey(obj)) {
struct pkcs15_pubkey_object *pubkey = (struct pkcs15_pubkey_object *) obj;
if (check_cert_data_read(fw_data, cert) == 0)
key = cert->cert_pubkey->pub_data;
if (!pubkey->pub_data)
continue;
if (sc_pkcs15_compare_id(&pubkey->pub_info->id, &prkey->prv_info->id)) {
prkey->prv_pubkey = pubkey;
key = pubkey->pub_data;
sc_log(context, "found friend public key %p", key);
}
}
}
}
}
@ -3180,18 +3456,142 @@ pkcs15_prkey_decrypt(struct sc_pkcs11_session *session, void *obj,
}
static CK_RV
pkcs15_prkey_derive(struct sc_pkcs11_session *session, void *obj,
CK_MECHANISM_PTR pMechanism,
CK_BYTE_PTR pParameters, CK_ULONG ulParametersLen,
CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
{
struct sc_pkcs11_card *p11card = session->slot->card;
struct pkcs15_fw_data *fw_data = NULL;
struct pkcs15_prkey_object *prkey = (struct pkcs15_prkey_object *) obj;
int need_unlock = 0;
int rv, flags = 0;
CK_BYTE_PTR pSeedData = NULL;
CK_ULONG ulSeedDataLen = 0;
sc_log(context, "Initiating derivation");
fw_data = (struct pkcs15_fw_data *) p11card->fws_data[session->slot->fw_data_idx];
if (!fw_data)
return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_DeriveKey");
sc_log(context, "derivation %p %p %p %p %d %p %d", session, obj, pMechanism, pParameters, ulParametersLen, pData, *pulDataLen);
/* See which of the alternative keys supports derivation */
while (prkey && !(prkey->prv_info->usage & SC_PKCS15_PRKEY_USAGE_DERIVE))
prkey = prkey->prv_next;
if (prkey == NULL)
return CKR_KEY_FUNCTION_NOT_PERMITTED;
if (pData != NULL && *pulDataLen > 0) { /* TODO DEE only test for NULL? */
need_unlock = 1;
rv = sc_lock(p11card->card);
if (rv < 0)
return sc_to_cryptoki_error(rv, "C_DeriveKey");
if (!sc_pkcs11_conf.lock_login) {
rv = reselect_app_df(fw_data->p15_card);
if (rv < 0) {
sc_unlock(p11card->card);
return sc_to_cryptoki_error(rv, "C_DeriveKey");
}
}
}
/* TODO DEE This may not be the place to get the parameters,
* But its the last PKCS11 aware routine.
* RSA parameters would be null.
*/
switch (prkey->base.p15_object->type) {
case SC_PKCS15_TYPE_PRKEY_EC:
{
CK_ECDH1_DERIVE_PARAMS * ecdh_params = (CK_ECDH1_DERIVE_PARAMS *) pParameters;
ulSeedDataLen = ecdh_params->ulPublicDataLen;
pSeedData = ecdh_params->pPublicData;
}
break;
}
rv = sc_pkcs15_derive(fw_data->p15_card, prkey->prv_p15obj,
flags, pSeedData, ulSeedDataLen,
pData, pulDataLen);
/* this may have been a request for size */
if (need_unlock)
sc_unlock(p11card->card);
sc_log(context, "Derivation complete. Result %d.", rv);
if (rv < 0)
return sc_to_cryptoki_error(rv, "C_DeriveKey");
return CKR_OK;
}
static CK_RV
pkcs15_prkey_can_do(struct sc_pkcs11_session *session, void *obj,
CK_MECHANISM_TYPE mech_type, unsigned int flags)
{
struct sc_pkcs11_card *p11card = session->slot->card;
struct pkcs15_fw_data *fw_data = NULL;
struct pkcs15_prkey_object *prkey = (struct pkcs15_prkey_object *) obj;
struct sc_pkcs15_prkey_info *pkinfo = NULL;
struct sc_supported_algo_info *token_algos = NULL;
int ii, jj;
if (!prkey || !prkey->prv_info)
return CKR_KEY_FUNCTION_NOT_PERMITTED;
pkinfo = prkey->prv_info;
/* Return in there are no usage algorithms specified for this key. */
if (!pkinfo->algo_refs[0])
return CKR_FUNCTION_NOT_SUPPORTED;
fw_data = (struct pkcs15_fw_data *) p11card->fws_data[session->slot->fw_data_idx];
token_algos = &fw_data->p15_card->tokeninfo->supported_algos[0];
for (ii=0;ii<SC_MAX_SUPPORTED_ALGORITHMS && pkinfo->algo_refs[ii];ii++) {
/* Look for algorithm supported by token referenced in the list of key's algorithms */
for (jj=0;jj<SC_MAX_SUPPORTED_ALGORITHMS && (token_algos + jj)->reference; jj++)
if (pkinfo->algo_refs[ii] == (token_algos + jj)->reference)
break;
if ((jj == SC_MAX_SUPPORTED_ALGORITHMS) || !(token_algos + jj)->reference)
return CKR_GENERAL_ERROR;
if ((token_algos + jj)->mechanism != mech_type)
continue;
if (flags == CKF_SIGN)
if ((token_algos + jj)->operations & SC_PKCS15_ALGO_OP_COMPUTE_SIGNATURE)
break;
if (flags == CKF_DECRYPT)
if ((token_algos + jj)->operations & SC_PKCS15_ALGO_OP_DECIPHER)
break;
}
if (ii == SC_MAX_SUPPORTED_ALGORITHMS || !pkinfo->algo_refs[ii])
return CKR_MECHANISM_INVALID;
return CKR_OK;
}
struct sc_pkcs11_object_ops pkcs15_prkey_ops = {
pkcs15_prkey_release,
pkcs15_prkey_set_attribute,
pkcs15_prkey_get_attribute,
sc_pkcs11_any_cmp_attribute,
pkcs15_any_destroy,
NULL,
NULL, /* get_size */
pkcs15_prkey_sign,
NULL, /* unwrap */
pkcs15_prkey_decrypt,
NULL, /* derive */
NULL /* can_do */
pkcs15_prkey_derive,
pkcs15_prkey_can_do
};
/*
@ -3532,6 +3932,172 @@ struct sc_pkcs11_object_ops pkcs15_dobj_ops = {
NULL /* can_do */
};
/* PKCS#15 Secret Key Objects */
/* TODO Currently only session objects */
static void
pkcs15_skey_release(void *object)
{
__pkcs15_release_object((struct pkcs15_any_object *) object);
}
static CK_RV
pkcs15_skey_set_attribute(struct sc_pkcs11_session *session,
void *object, CK_ATTRIBUTE_PTR attr)
{
struct pkcs15_skey_object *skey = (struct pkcs15_skey_object*) object;
/* TODO DEE Assume a session based token, and only
* change in memory, and only selected types
* The pkcs15_set_attrib assumes the object is on the card....
* When skey support on the card is added this needs to be changed */
switch (attr->type) {
case CKA_VALUE:
if (attr->pValue) {
skey->info->data.value = calloc(1,attr->ulValueLen);
if (!skey->info->data.value)
return CKR_HOST_MEMORY;
memcpy(skey->info->data.value, attr->pValue, attr->ulValueLen);
skey->info->data.len = attr->ulValueLen;
}
break;
default:
return pkcs15_set_attrib(session, skey->base.p15_object, attr);
}
return CKR_OK;
}
#if 0
static int pkcs15_skey_get_value(struct sc_pkcs11_session *session,
struct pkcs15_skey_object *skey,
struct sc_pkcs15_skey **out_data)
{
int rv;
struct sc_pkcs15_skey * skey_data = NULL;
struct pkcs15_fw_data *fw_data =
(struct pkcs15_fw_data *) session->slot->card->fw_data;
sc_card_t *card = session->slot->card->card;
if (!out_data)
return SC_ERROR_INVALID_ARGUMENTS;
/*TODO could try and read extractable secret keys
* but for now we only work with session objects
* derived from other keys
*/
skey_data= malloc(sizeof(struct sc_pkcs15_skey));
if (skey_data == NULL)
return SC_ERROR_OUT_OF_MEMORY;
memset(skey_data, 0, sizeof(struct sc_pkcs15_skey));
if (skey->value && skey->value->data_len) {
skey_data->data = malloc(skey_data->data_len);
if (skey_data->data == NULL) {
free(skey_data);
return SC_ERROR_OUT_OF_MEMORY;
}
skey_data->data_len = skey->value->data_len;
memcpy(skey_data->data, skey->value->data, skey->value->data_len);
return 0;
}
*out_data = skey_data;
return 0;
}
#endif
static CK_RV
pkcs15_skey_get_attribute(struct sc_pkcs11_session *session,
void *object, CK_ATTRIBUTE_PTR attr)
{
struct pkcs15_skey_object *skey = (struct pkcs15_skey_object*) object;
size_t len;
switch (attr->type) {
case CKA_CLASS:
check_attribute_buffer(attr, sizeof(CK_OBJECT_CLASS));
*(CK_OBJECT_CLASS*)attr->pValue = CKO_SECRET_KEY;
break;
case CKA_TOKEN:
/*TODO DEE change if on card skeys are supported */
check_attribute_buffer(attr, sizeof(CK_BBOOL));
*(CK_BBOOL*)attr->pValue = FALSE;
break;
case CKA_PRIVATE:
check_attribute_buffer(attr, sizeof(CK_BBOOL));
*(CK_BBOOL*)attr->pValue = (skey->base.p15_object->flags & SC_PKCS15_CO_FLAG_PRIVATE) != 0;
break;
case CKA_MODIFIABLE:
check_attribute_buffer(attr, sizeof(CK_BBOOL));
*(CK_BBOOL*)attr->pValue = (skey->base.p15_object->flags & 0x02) != 0;
/*TODO Why no definition of the flag */
break;
case CKA_LABEL:
len = strlen(skey->base.p15_object->label);
check_attribute_buffer(attr, len);
memcpy(attr->pValue, skey->base.p15_object->label, len);
break;
case CKA_KEY_TYPE:
check_attribute_buffer(attr, sizeof(CK_KEY_TYPE));
if (skey->info)
*(CK_OBJECT_CLASS*)attr->pValue = skey->info->key_type;
break;
case CKA_ENCRYPT:
case CKA_DECRYPT:
case CKA_SIGN:
case CKA_SIGN_RECOVER:
case CKA_WRAP:
case CKA_UNWRAP:
case CKA_VERIFY:
case CKA_VERIFY_RECOVER:
case CKA_DERIVE:
if (skey->info)
return get_usage_bit(skey->info->usage, attr);
else
return get_usage_bit(SC_PKCS15_PRKEY_USAGE_ENCRYPT
|SC_PKCS15_PRKEY_USAGE_DECRYPT
|SC_PKCS15_PRKEY_USAGE_WRAP
|SC_PKCS15_PRKEY_USAGE_UNWRAP, attr);
break;
case CKA_ID:
check_attribute_buffer(attr, skey->info->id.len);
memcpy(attr->pValue, skey->info->id.value, skey->info->id.len);
break;
case CKA_VALUE_LEN:
check_attribute_buffer(attr, sizeof(CK_ULONG));
*(CK_ULONG*)attr->pValue = skey->info->data.len;
break;
case CKA_VALUE:
check_attribute_buffer(attr, skey->info->data.len);
memcpy(attr->pValue, skey->info->data.value, skey->info->data.len);
break;
default:
return CKR_ATTRIBUTE_TYPE_INVALID;
}
return CKR_OK;
}
/*
* Secret key objects, currently used only to retrieve derived session key
*/
struct sc_pkcs11_object_ops pkcs15_skey_ops = {
pkcs15_skey_release,
pkcs15_skey_set_attribute,
pkcs15_skey_get_attribute,
sc_pkcs11_any_cmp_attribute,
pkcs15_skey_destroy,
NULL, /* get_size */
NULL, /* sign */
NULL, /* unwrap_key */
NULL, /* decrypt */
NULL, /* derive */
NULL /* can_do */
};
/*
* get_attribute helpers
*/
@ -3803,6 +4369,24 @@ static int register_ec_mechanisms(struct sc_pkcs11_card *p11card, int flags,
if (rc != CKR_OK)
return rc;
#endif
/* ADD ECDH mechanisms */
/* The PIV uses curves where CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE produce the same results */
mech_info.flags &= ~CKF_SIGN;
mech_info.flags |= CKF_DERIVE;
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_COFACTOR_DERIVE, &mech_info, CKK_EC, NULL);
rc = sc_pkcs11_register_mechanism(p11card, mt);
if (rc != CKR_OK)
return rc;
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_DERIVE, &mech_info, CKK_EC, NULL);
rc = sc_pkcs11_register_mechanism(p11card, mt);
if (rc != CKR_OK)
return rc;
if (flags & SC_ALGORITHM_ONBOARD_KEY_GEN) {
mech_info.flags = CKF_HW | CKF_GENERATE_KEY_PAIR;
mech_info.flags |= ec_flags;
@ -3814,22 +4398,9 @@ static int register_ec_mechanisms(struct sc_pkcs11_card *p11card, int flags,
return rc;
}
#if 0
/* TODO: -DEE Add CKM_ECDH1_COFACTOR_DERIVE as PIV can do this */
/* TODO: -DEE But this requires C_DeriveKey to be implemented */
mech_info.flags &= ~CKF_SIGN;
mech_info.flags |= CKF_DRIVE;
sc_pkcs11_new_fw_mechanism(CKM_ECDH1_COFACTOR_DERIVE,
CKM_ECDH1_COFACTOR_DERIVE, NULL);
#endif
return CKR_OK;
}
/*
* Mechanism handling
* FIXME: We should consult the card's algorithm list to
@ -3981,7 +4552,9 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
return CKR_OK;
}
static int lock_card(struct pkcs15_fw_data *fw_data)
static int
lock_card(struct pkcs15_fw_data *fw_data)
{
int rc;
@ -3993,7 +4566,9 @@ static int lock_card(struct pkcs15_fw_data *fw_data)
return rc;
}
static int unlock_card(struct pkcs15_fw_data *fw_data)
static int
unlock_card(struct pkcs15_fw_data *fw_data)
{
while (fw_data->locked) {
sc_unlock(fw_data->p15_card->card);
@ -4003,13 +4578,13 @@ static int unlock_card(struct pkcs15_fw_data *fw_data)
}
static int reselect_app_df(sc_pkcs15_card_t *p15card)
static int
reselect_app_df(sc_pkcs15_card_t *p15card)
{
int r = SC_SUCCESS;
if (p15card->file_app != NULL) {
/* if the application df (of the pkcs15 application) is
* specified select it */
/* if the application df (of the pkcs15 application) is specified select it */
sc_path_t *tpath = &p15card->file_app->path;
sc_log(p15card->card->ctx, "reselect application df");
r = sc_select_file(p15card->card, tpath, NULL);

View File

@ -151,18 +151,18 @@ sc_pkcs11_md_init(struct sc_pkcs11_session *session,
sc_pkcs11_mechanism_type_t *mt;
int rv;
if (!session || !session->slot
|| !(p11card = session->slot->card))
return CKR_ARGUMENTS_BAD;
LOG_FUNC_CALLED(context);
if (!session || !session->slot || !(p11card = session->slot->card))
LOG_FUNC_RETURN(context, CKR_ARGUMENTS_BAD);
/* See if we support this mechanism type */
mt = sc_pkcs11_find_mechanism(p11card, pMechanism->mechanism, CKF_DIGEST);
if (mt == NULL)
return CKR_MECHANISM_INVALID;
LOG_FUNC_RETURN(context, CKR_MECHANISM_INVALID);
rv = session_start_operation(session, SC_PKCS11_OPERATION_DIGEST, mt, &operation);
if (rv != CKR_OK)
return rv;
LOG_FUNC_RETURN(context, rv);
memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM));
@ -171,7 +171,7 @@ sc_pkcs11_md_init(struct sc_pkcs11_session *session,
if (rv != CKR_OK)
session_stop_operation(session, SC_PKCS11_OPERATION_DIGEST);
return rv;
LOG_FUNC_RETURN(context, rv);
}
CK_RV
@ -191,7 +191,7 @@ done:
if (rv != CKR_OK)
session_stop_operation(session, SC_PKCS11_OPERATION_DIGEST);
return rv;
LOG_FUNC_RETURN(context, rv);
}
CK_RV
@ -203,19 +203,18 @@ sc_pkcs11_md_final(struct sc_pkcs11_session *session,
rv = session_get_operation(session, SC_PKCS11_OPERATION_DIGEST, &op);
if (rv != CKR_OK)
return rv;
LOG_FUNC_RETURN(context, rv);
/* This is a request for the digest length */
if (pData == NULL)
*pulDataLen = 0;
rv = op->type->md_final(op, pData, pulDataLen);
if (rv == CKR_BUFFER_TOO_SMALL)
return pData == NULL ? CKR_OK : rv;
LOG_FUNC_RETURN(context, pData == NULL ? CKR_OK : CKR_BUFFER_TOO_SMALL);
session_stop_operation(session, SC_PKCS11_OPERATION_DIGEST);
return rv;
LOG_FUNC_RETURN(context, rv);
}
/*
@ -223,40 +222,38 @@ sc_pkcs11_md_final(struct sc_pkcs11_session *session,
* the key object is capable of signing _something_
*/
CK_RV
sc_pkcs11_sign_init(struct sc_pkcs11_session *session,
CK_MECHANISM_PTR pMechanism,
struct sc_pkcs11_object *key,
CK_MECHANISM_TYPE key_type)
sc_pkcs11_sign_init(struct sc_pkcs11_session *session, CK_MECHANISM_PTR pMechanism,
struct sc_pkcs11_object *key, CK_MECHANISM_TYPE key_type)
{
struct sc_pkcs11_card *p11card;
sc_pkcs11_operation_t *operation;
sc_pkcs11_mechanism_type_t *mt;
int rv;
if (!session || !session->slot
|| !(p11card = session->slot->card))
return CKR_ARGUMENTS_BAD;
LOG_FUNC_CALLED(context);
if (!session || !session->slot || !(p11card = session->slot->card))
LOG_FUNC_RETURN(context, CKR_ARGUMENTS_BAD);
/* See if we support this mechanism type */
sc_log(context, "mechanism 0x%X, key-type 0x%X", pMechanism->mechanism, key_type);
mt = sc_pkcs11_find_mechanism(p11card, pMechanism->mechanism, CKF_SIGN);
if (mt == NULL)
return CKR_MECHANISM_INVALID;
LOG_FUNC_RETURN(context, CKR_MECHANISM_INVALID);
/* See if compatible with key type */
if (mt->key_type != key_type)
return CKR_KEY_TYPE_INCONSISTENT;
LOG_FUNC_RETURN(context, CKR_KEY_TYPE_INCONSISTENT);
rv = session_start_operation(session, SC_PKCS11_OPERATION_SIGN, mt, &operation);
if (rv != CKR_OK)
return rv;
LOG_FUNC_RETURN(context, rv);
memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM));
rv = mt->sign_init(operation, key);
if (rv != CKR_OK)
session_stop_operation(session, SC_PKCS11_OPERATION_SIGN);
return rv;
LOG_FUNC_RETURN(context, rv);
}
CK_RV
@ -266,9 +263,10 @@ sc_pkcs11_sign_update(struct sc_pkcs11_session *session,
sc_pkcs11_operation_t *op;
int rv;
LOG_FUNC_CALLED(context);
rv = session_get_operation(session, SC_PKCS11_OPERATION_SIGN, &op);
if (rv != CKR_OK)
return rv;
LOG_FUNC_RETURN(context, rv);
if (op->type->sign_update == NULL) {
rv = CKR_KEY_TYPE_INCONSISTENT;
@ -281,7 +279,7 @@ done:
if (rv != CKR_OK)
session_stop_operation(session, SC_PKCS11_OPERATION_SIGN);
return rv;
LOG_FUNC_RETURN(context, rv);
}
CK_RV
@ -291,9 +289,10 @@ sc_pkcs11_sign_final(struct sc_pkcs11_session *session,
sc_pkcs11_operation_t *op;
int rv;
LOG_FUNC_CALLED(context);
rv = session_get_operation(session, SC_PKCS11_OPERATION_SIGN, &op);
if (rv != CKR_OK)
return rv;
LOG_FUNC_RETURN(context, rv);
/* Bail out for signature mechanisms that don't do hashing */
if (op->type->sign_final == NULL) {
@ -307,7 +306,7 @@ done:
if (rv != CKR_BUFFER_TOO_SMALL && pSignature != NULL)
session_stop_operation(session, SC_PKCS11_OPERATION_SIGN);
return rv;
LOG_FUNC_RETURN(context, rv);
}
CK_RV
@ -318,7 +317,7 @@ sc_pkcs11_sign_size(struct sc_pkcs11_session *session, CK_ULONG_PTR pLength)
rv = session_get_operation(session, SC_PKCS11_OPERATION_SIGN, &op);
if (rv != CKR_OK)
return rv;
LOG_FUNC_RETURN(context, rv);
/* Bail out for signature mechanisms that don't do hashing */
if (op->type->sign_size == NULL) {
@ -332,7 +331,7 @@ done:
if (rv != CKR_OK)
session_stop_operation(session, SC_PKCS11_OPERATION_SIGN);
return rv;
LOG_FUNC_RETURN(context, rv);
}
/*
@ -340,25 +339,44 @@ done:
*/
static CK_RV
sc_pkcs11_signature_init(sc_pkcs11_operation_t *operation,
struct sc_pkcs11_object *key)
struct sc_pkcs11_object *key)
{
struct hash_signature_info *info;
struct signature_data *data;
int rv;
CK_RV rv;
int can_do_it = 0;
LOG_FUNC_CALLED(context);
if (!(data = calloc(1, sizeof(*data))))
return CKR_HOST_MEMORY;
LOG_FUNC_RETURN(context, CKR_HOST_MEMORY);
data->info = NULL;
data->key = key;
/* If this is a signature with hash operation, set up the
* hash operation */
if (key->ops->can_do) {
rv = key->ops->can_do(operation->session, key, operation->type->mech, CKF_SIGN);
if (rv == CKR_OK) {
/* Mechanism recognised and can be performed by pkcs#15 card */
can_do_it = 1;
}
else if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
/* Mechanism not recognised by pkcs#15 card */
can_do_it = 0;
}
else {
/* Mechanism recognised but cannot be performed by pkcs#15 card, or some general error. */
free(data);
LOG_FUNC_RETURN(context, rv);
}
}
/* If this is a signature with hash operation,
* and card cannot perform itself signature with hash operation,
* set up the hash operation */
info = (struct hash_signature_info *) operation->type->mech_data;
if (info != NULL) {
if (info != NULL && !can_do_it) {
/* Initialize hash operation */
data->md = sc_pkcs11_new_operation(operation->session,
info->hash_type);
data->md = sc_pkcs11_new_operation(operation->session, info->hash_type);
if (data->md == NULL)
rv = CKR_HOST_MEMORY;
else
@ -366,46 +384,48 @@ sc_pkcs11_signature_init(sc_pkcs11_operation_t *operation,
if (rv != CKR_OK) {
sc_pkcs11_release_operation(&data->md);
free(data);
return rv;
LOG_FUNC_RETURN(context, rv);
}
data->info = info;
}
operation->priv_data = data;
return CKR_OK;
LOG_FUNC_RETURN(context, CKR_OK);
}
static CK_RV
sc_pkcs11_signature_update(sc_pkcs11_operation_t *operation,
CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
{
struct signature_data *data;
LOG_FUNC_CALLED(context);
sc_log(context, "data part length %li", ulPartLen);
data = (struct signature_data *) operation->priv_data;
if (data->md) {
sc_pkcs11_operation_t *md = data->md;
return md->type->md_update(md, pPart, ulPartLen);
CK_RV rv = data->md->type->md_update(data->md, pPart, ulPartLen);
LOG_FUNC_RETURN(context, rv);
}
/* This signature mechanism operates on the raw data */
if (data->buffer_len + ulPartLen > sizeof(data->buffer))
return CKR_DATA_LEN_RANGE;
LOG_FUNC_RETURN(context, CKR_DATA_LEN_RANGE);
memcpy(data->buffer + data->buffer_len, pPart, ulPartLen);
data->buffer_len += ulPartLen;
return CKR_OK;
sc_log(context, "data length %li", data->buffer_len);
LOG_FUNC_RETURN(context, CKR_OK);
}
static CK_RV
sc_pkcs11_signature_final(sc_pkcs11_operation_t *operation,
CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
{
struct signature_data *data;
struct sc_pkcs11_object *key;
int rv;
CK_RV rv;
LOG_FUNC_CALLED(context);
data = (struct signature_data *) operation->priv_data;
sc_log(context, "data length %li", data->buffer_len);
if (data->md) {
sc_pkcs11_operation_t *md = data->md;
CK_ULONG len = sizeof(data->buffer);
@ -414,15 +434,14 @@ sc_pkcs11_signature_final(sc_pkcs11_operation_t *operation,
if (rv == CKR_BUFFER_TOO_SMALL)
rv = CKR_FUNCTION_FAILED;
if (rv != CKR_OK)
return rv;
LOG_FUNC_RETURN(context, rv);
data->buffer_len = len;
}
key = data->key;
return key->ops->sign(operation->session,
key, &operation->mechanism,
data->buffer, data->buffer_len,
pSignature, pulSignatureLen);
sc_log(context, "%li bytes to sign", data->buffer_len);
rv = data->key->ops->sign(operation->session, data->key, &operation->mechanism,
data->buffer, data->buffer_len, pSignature, pulSignatureLen);
LOG_FUNC_RETURN(context, rv);
}
static CK_RV
@ -465,7 +484,7 @@ sc_pkcs11_signature_size(sc_pkcs11_operation_t *operation, CK_ULONG_PTR pLength)
}
}
return rv;
LOG_FUNC_RETURN(context, rv);
}
static void
@ -474,6 +493,8 @@ sc_pkcs11_signature_release(sc_pkcs11_operation_t *operation)
struct signature_data *data;
data = (struct signature_data *) operation->priv_data;
if (!data)
return;
sc_pkcs11_release_operation(&data->md);
memset(data, 0, sizeof(*data));
free(data);
@ -485,10 +506,8 @@ sc_pkcs11_signature_release(sc_pkcs11_operation_t *operation)
* the key object is capable of verifying _something_
*/
CK_RV
sc_pkcs11_verif_init(struct sc_pkcs11_session *session,
CK_MECHANISM_PTR pMechanism,
struct sc_pkcs11_object *key,
CK_MECHANISM_TYPE key_type)
sc_pkcs11_verif_init(struct sc_pkcs11_session *session, CK_MECHANISM_PTR pMechanism,
struct sc_pkcs11_object *key, CK_MECHANISM_TYPE key_type)
{
struct sc_pkcs11_card *p11card;
sc_pkcs11_operation_t *operation;
@ -741,6 +760,104 @@ sc_pkcs11_decr(struct sc_pkcs11_session *session,
return rv;
}
/* Derive one key from another, and return results in created object */
CK_RV
sc_pkcs11_deri(struct sc_pkcs11_session *session,
CK_MECHANISM_PTR pMechanism,
struct sc_pkcs11_object * basekey,
CK_KEY_TYPE key_type,
CK_SESSION_HANDLE hSession,
CK_OBJECT_HANDLE hdkey,
struct sc_pkcs11_object * dkey)
{
struct sc_pkcs11_card *p11card;
sc_pkcs11_operation_t *operation;
sc_pkcs11_mechanism_type_t *mt;
CK_BYTE_PTR keybuf = NULL;
CK_ULONG ulDataLen = 0;
CK_ATTRIBUTE template[] = {
{CKA_VALUE, keybuf, 0}
};
CK_RV rv;
if (!session || !session->slot
|| !(p11card = session->slot->card))
return CKR_ARGUMENTS_BAD;
/* See if we support this mechanism type */
mt = sc_pkcs11_find_mechanism(p11card, pMechanism->mechanism, CKF_DERIVE);
if (mt == NULL)
return CKR_MECHANISM_INVALID;
/* See if compatible with key type */
if (mt->key_type != key_type)
return CKR_KEY_TYPE_INCONSISTENT;
rv = session_start_operation(session, SC_PKCS11_OPERATION_DERIVE, mt, &operation);
if (rv != CKR_OK)
return rv;
memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM));
/* Get the size of the data to be returned
* If the card could derive a key an leave it on the card
* then no data is returned.
* If the card returns the data, we will store it in the sercet key CKA_VALUE
*/
ulDataLen = 0;
rv = operation->type->derive(operation, basekey,
pMechanism->pParameter, pMechanism->ulParameterLen,
NULL, &ulDataLen);
if (rv != CKR_OK)
goto out;
if (ulDataLen > 0)
keybuf = calloc(1,ulDataLen);
else
keybuf = calloc(1,8); /* pass in dummy buffer */
if (!keybuf) {
rv = CKR_HOST_MEMORY;
goto out;
}
/* Now do the actuall derivation */
rv = operation->type->derive(operation, basekey,
pMechanism->pParameter, pMechanism->ulParameterLen,
keybuf, &ulDataLen);
if (rv != CKR_OK)
goto out;
/* add the CKA_VALUE attribute to the template if it was returned
* if not assume it is on the card...
* But for now PIV with ECDH returns the generic key data
* TODO need to support truncation, if CKA_VALUE_LEN < ulDataLem
*/
if (ulDataLen > 0) {
template[0].pValue = keybuf;
template[0].ulValueLen = ulDataLen;
dkey->ops->set_attribute(session, dkey, &template[0]);
memset(keybuf,0,ulDataLen);
}
out:
session_stop_operation(session, SC_PKCS11_OPERATION_DERIVE);
if (keybuf)
free(keybuf);
return rv;
}
/*
* Initialize a signature operation
*/
@ -776,6 +893,19 @@ sc_pkcs11_decrypt(sc_pkcs11_operation_t *operation,
pData, pulDataLen);
}
static CK_RV
sc_pkcs11_derive(sc_pkcs11_operation_t *operation,
struct sc_pkcs11_object *basekey,
CK_BYTE_PTR pmechParam, CK_ULONG ulmechParamLen,
CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
{
return basekey->ops->derive(operation->session,
basekey,
&operation->mechanism,
pmechParam, ulmechParamLen,
pData, pulDataLen);
}
/*
* Create new mechanism type for a mechanism supported by
* the card
@ -814,7 +944,7 @@ sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE mech,
/* TODO */
}
if (pInfo->flags & CKF_DERIVE) {
/* TODO: -DEE CKM_ECDH1_COFACTOR_DERIVE for PIV */
mt->derive = sc_pkcs11_derive;
}
if (pInfo->flags & CKF_DECRYPT) {
mt->decrypt_init = sc_pkcs11_decrypt_init;

View File

@ -34,7 +34,9 @@ struct sc_to_cryptoki_error_conversion {
};
static struct sc_to_cryptoki_error_conversion sc_to_cryptoki_error_map[] = {
{ "C_GenerateKeyPair", SC_ERROR_INVALID_PIN_LENGTH, CKR_GENERAL_ERROR },
{ "C_GenerateKeyPair", SC_ERROR_INVALID_PIN_LENGTH, CKR_GENERAL_ERROR },
{ "C_Sign", SC_ERROR_NOT_ALLOWED, CKR_FUNCTION_FAILED},
{ "C_Decrypt", SC_ERROR_NOT_ALLOWED, CKR_FUNCTION_FAILED},
{NULL, 0, 0}
};
@ -199,11 +201,13 @@ CK_RV attr_extract(CK_ATTRIBUTE_PTR pAttr, void *ptr, size_t * sizep)
size = sizeof(CK_KEY_TYPE);
break;
case CKA_PRIVATE:
case CKA_TOKEN:
size = sizeof(CK_BBOOL);
break;
case CKA_CERTIFICATE_TYPE:
size = sizeof(CK_CERTIFICATE_TYPE);
break;
case CKA_VALUE_LEN:
case CKA_MODULUS_BITS:
size = sizeof(CK_ULONG);
break;

View File

@ -50,25 +50,26 @@ static sc_pkcs11_mechanism_type_t find_mechanism = {
NULL /* mech_data */
};
static void sc_find_release(sc_pkcs11_operation_t *operation)
static void
sc_find_release(sc_pkcs11_operation_t *operation)
{
struct sc_pkcs11_find_operation *fop =
(struct sc_pkcs11_find_operation *)operation;
struct sc_pkcs11_find_operation *fop = (struct sc_pkcs11_find_operation *)operation;
sc_log(context,"freeing %d handles used %d at %p",
fop->allocated_handles, fop->num_handles, fop->handles);
sc_log(context,"freeing %d handles used %d at %p", fop->allocated_handles, fop->num_handles, fop->handles);
if (fop->handles) {
free(fop->handles);
fop->handles = NULL;
}
}
static CK_RV get_object_from_session(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
struct sc_pkcs11_session **session,
struct sc_pkcs11_object **object)
static CK_RV
get_object_from_session(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
struct sc_pkcs11_session **session, struct sc_pkcs11_object **object)
{
CK_RV rv;
struct sc_pkcs11_session *sess;
CK_RV rv;
rv = get_session(hSession, &sess);
if (rv != CKR_OK)
return rv;
@ -80,23 +81,29 @@ static CK_RV get_object_from_session(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDL
return CKR_OK;
}
CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
CK_ULONG ulCount, /* attributes in template */
CK_OBJECT_HANDLE_PTR phObject)
{ /* receives new object's handle. */
CK_RV rv;
/* C_CreateObject can be called from C_DeriveKey
* which is holding the sc_pkcs11_lock
* So dont get the lock again. */
static
CK_RV sc_create_object_int(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
CK_ULONG ulCount, /* attributes in template */
CK_OBJECT_HANDLE_PTR phObject, /* receives new object's handle. */
int use_lock)
{
CK_RV rv = CKR_OK;
struct sc_pkcs11_session *session;
struct sc_pkcs11_card *card;
LOG_FUNC_CALLED(context);
if (pTemplate == NULL_PTR || ulCount == 0)
return CKR_ARGUMENTS_BAD;
rv = sc_pkcs11_lock();
if (rv != CKR_OK)
if (use_lock) {
rv = sc_pkcs11_lock();
if (rv != CKR_OK)
return rv;
LOG_FUNC_CALLED(context);
}
dump_template(SC_LOG_DEBUG_NORMAL, "C_CreateObject()", pTemplate, ulCount);
@ -106,48 +113,68 @@ CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, /* the session's handle */
goto out;
}
#if 0
/* TODO DEE what should we check here */
if (!(session->flags & CKF_RW_SESSION)) {
rv = CKR_SESSION_READ_ONLY;
goto out;
}
#endif
card = session->slot->card;
if (card->framework->create_object == NULL)
rv = CKR_FUNCTION_NOT_SUPPORTED;
else
rv = card->framework->create_object(session->slot, pTemplate, ulCount, phObject);
out: sc_pkcs11_unlock();
out:
if (use_lock)
sc_pkcs11_unlock();
LOG_FUNC_RETURN(context, rv);
}
CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject, /* the object's handle */
CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
CK_ULONG ulCount, /* attributes in template */
CK_OBJECT_HANDLE_PTR phNewObject)/* receives handle of copy */
CK_RV
C_CreateObject(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
CK_ULONG ulCount, /* attributes in template */
CK_OBJECT_HANDLE_PTR phObject)
{
return sc_create_object_int(hSession, pTemplate, ulCount, phObject, 1);
}
CK_RV
C_CopyObject(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject, /* the object's handle */
CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
CK_ULONG ulCount, /* attributes in template */
CK_OBJECT_HANDLE_PTR phNewObject) /* receives handle of copy */
{
return CKR_FUNCTION_NOT_SUPPORTED;
}
CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject)
{ /* the object's handle */
CK_RV
C_DestroyObject(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject) /* the object's handle */
{
CK_RV rv;
struct sc_pkcs11_session *session;
struct sc_pkcs11_object *object;
CK_BBOOL is_token = FALSE;
CK_ATTRIBUTE token_attribure = {CKA_TOKEN, &is_token, sizeof(is_token)};
rv = sc_pkcs11_lock();
if (rv != CKR_OK)
return rv;
sc_log(context, "C_DestroyObject(hSession=0x%lx, hObject=0x%lx)", hSession, hObject);
rv = get_object_from_session(hSession, hObject, &session, &object);
if (rv != CKR_OK)
goto out;
if (!(session->flags & CKF_RW_SESSION)) {
object->ops->get_attribute(session, object, &token_attribure);
if (is_token == TRUE && !(session->flags & CKF_RW_SESSION)) {
rv = CKR_SESSION_READ_ONLY;
goto out;
}
@ -157,22 +184,27 @@ CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, /* the session's handle */
else
rv = object->ops->destroy_object(session, object);
out: sc_pkcs11_unlock();
out:
sc_pkcs11_unlock();
return rv;
}
CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_RV
C_GetObjectSize(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject, /* the object's handle */
CK_ULONG_PTR pulSize)
{ /* receives size of object */
CK_ULONG_PTR pulSize) /* receives size of object */
{
return CKR_FUNCTION_NOT_SUPPORTED;
}
CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject, /* the object's handle */
CK_ATTRIBUTE_PTR pTemplate, /* specifies attributes, gets values */
CK_ULONG ulCount)
{ /* attributes in template */
CK_RV
C_GetAttributeValue(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject, /* the object's handle */
CK_ATTRIBUTE_PTR pTemplate, /* specifies attributes, gets values */
CK_ULONG ulCount) /* attributes in template */
{
static int precedence[] = {
CKR_OK,
CKR_BUFFER_TOO_SMALL,
@ -235,11 +267,13 @@ out: sc_log(context, "C_GetAttributeValue(hSession=0x%lx, hObject=0x%lx) = %s",
return rv;
}
CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject, /* the object's handle */
CK_ATTRIBUTE_PTR pTemplate, /* specifies attributes and values */
CK_ULONG ulCount)
{ /* attributes in template */
CK_RV
C_SetAttributeValue(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject, /* the object's handle */
CK_ATTRIBUTE_PTR pTemplate, /* specifies attributes and values */
CK_ULONG ulCount) /* attributes in template */
{
CK_RV rv;
unsigned int i;
struct sc_pkcs11_session *session;
@ -273,14 +307,17 @@ CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession, /* the session's handle */
}
}
out: sc_pkcs11_unlock();
out:
sc_pkcs11_unlock();
return rv;
}
CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
CK_ULONG ulCount)
{ /* attributes in search template */
CK_RV
C_FindObjectsInit(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
CK_ULONG ulCount) /* attributes in search template */
{
CK_RV rv;
CK_BBOOL is_private = TRUE;
CK_ATTRIBUTE private_attribute = { CKA_PRIVATE, &is_private, sizeof(is_private) };
@ -374,15 +411,18 @@ CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, /* the session's handle */
sc_log(context, "%d matching objects\n", operation->num_handles);
out: sc_pkcs11_unlock();
out:
sc_pkcs11_unlock();
return rv;
}
CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE_PTR phObject, /* receives object handle array */
CK_ULONG ulMaxObjectCount, /* max handles to be returned */
CK_ULONG_PTR pulObjectCount)
{ /* actual number returned */
CK_RV
C_FindObjects(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE_PTR phObject, /* receives object handle array */
CK_ULONG ulMaxObjectCount, /* max handles to be returned */
CK_ULONG_PTR pulObjectCount) /* actual number returned */
{
CK_RV rv;
CK_ULONG to_return;
struct sc_pkcs11_session *session;
@ -399,8 +439,7 @@ CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, /* the session's handle */
if (rv != CKR_OK)
goto out;
rv = session_get_operation(session, SC_PKCS11_OPERATION_FIND,
(sc_pkcs11_operation_t **) & operation);
rv = session_get_operation(session, SC_PKCS11_OPERATION_FIND, (sc_pkcs11_operation_t **) & operation);
if (rv != CKR_OK)
goto out;
@ -410,9 +449,7 @@ CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, /* the session's handle */
*pulObjectCount = to_return;
memcpy(phObject,
&operation->handles[operation->current_handle],
to_return * sizeof(CK_OBJECT_HANDLE));
memcpy(phObject, &operation->handles[operation->current_handle], to_return * sizeof(CK_OBJECT_HANDLE));
operation->current_handle += to_return;
@ -420,8 +457,10 @@ out: sc_pkcs11_unlock();
return rv;
}
CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
{ /* the session's handle */
CK_RV
C_FindObjectsFinal(CK_SESSION_HANDLE hSession) /* the session's handle */
{
CK_RV rv;
struct sc_pkcs11_session *session;
@ -445,10 +484,10 @@ out: sc_pkcs11_unlock();
* Below here all functions are wrappers to pass all object attribute and method
* handling to appropriate object layer.
*/
CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism)
{ /* the digesting mechanism */
CK_RV
C_DigestInit(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism) /* the digesting mechanism */
{
CK_RV rv;
struct sc_pkcs11_session *session;
@ -469,12 +508,14 @@ CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, /* the session's handle */
return rv;
}
CK_RV C_Digest(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pData, /* data to be digested */
CK_ULONG ulDataLen, /* bytes of data to be digested */
CK_BYTE_PTR pDigest, /* receives the message digest */
CK_ULONG_PTR pulDigestLen)
{ /* receives byte length of digest */
CK_RV
C_Digest(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pData, /* data to be digested */
CK_ULONG ulDataLen, /* bytes of data to be digested */
CK_BYTE_PTR pDigest, /* receives the message digest */
CK_ULONG_PTR pulDigestLen) /* receives byte length of digest */
{
CK_RV rv;
struct sc_pkcs11_session *session;
@ -496,10 +537,12 @@ out: sc_log(context, "C_Digest() = %s", lookup_enum ( RV_T, rv ));
return rv;
}
CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pPart, /* data to be digested */
CK_ULONG ulPartLen)
{ /* bytes of data to be digested */
CK_RV
C_DigestUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pPart, /* data to be digested */
CK_ULONG ulPartLen) /* bytes of data to be digested */
{
CK_RV rv;
struct sc_pkcs11_session *session;
@ -516,16 +559,20 @@ CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
return rv;
}
CK_RV C_DigestKey(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hKey)
{ /* handle of secret key to digest */
CK_RV
C_DigestKey(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hKey) /* handle of secret key to digest */
{
return CKR_FUNCTION_NOT_SUPPORTED;
}
CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pDigest, /* receives the message digest */
CK_ULONG_PTR pulDigestLen)
{ /* receives byte count of digest */
CK_RV
C_DigestFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pDigest, /* receives the message digest */
CK_ULONG_PTR pulDigestLen) /* receives byte count of digest */
{
CK_RV rv;
struct sc_pkcs11_session *session;
@ -542,17 +589,19 @@ CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
return rv;
}
CK_RV C_SignInit(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
CK_OBJECT_HANDLE hKey)
{ /* handle of the signature key */
CK_RV rv;
CK_RV
C_SignInit(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
CK_OBJECT_HANDLE hKey) /* handle of the signature key */
{
CK_BBOOL can_sign;
CK_KEY_TYPE key_type;
CK_ATTRIBUTE sign_attribute = { CKA_SIGN, &can_sign, sizeof(can_sign) };
CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
struct sc_pkcs11_session *session;
struct sc_pkcs11_object *object;
CK_RV rv;
if (pMechanism == NULL_PTR)
return CKR_ARGUMENTS_BAD;
@ -586,17 +635,20 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, /* the session's handle */
rv = sc_pkcs11_sign_init(session, pMechanism, object, key_type);
out: sc_log(context, "C_SignInit() = %s", lookup_enum ( RV_T, rv ));
out:
sc_log(context, "C_SignInit() = %s", lookup_enum ( RV_T, rv ));
sc_pkcs11_unlock();
return rv;
}
CK_RV C_Sign(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pData, /* the data (digest) to be signed */
CK_ULONG ulDataLen, /* count of bytes to be signed */
CK_BYTE_PTR pSignature, /* receives the signature */
CK_ULONG_PTR pulSignatureLen)
{ /* receives byte count of signature */
CK_RV
C_Sign(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pData, /* the data (digest) to be signed */
CK_ULONG ulDataLen, /* count of bytes to be signed */
CK_BYTE_PTR pSignature, /* receives the signature */
CK_ULONG_PTR pulSignatureLen) /* receives byte count of signature */
{
CK_RV rv;
struct sc_pkcs11_session *session;
CK_ULONG length;
@ -627,15 +679,18 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, /* the session's handle */
if (rv == CKR_OK)
rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen);
out: sc_log(context, "C_Sign() = %s", lookup_enum ( RV_T, rv ));
out:
sc_log(context, "C_Sign() = %s", lookup_enum ( RV_T, rv ));
sc_pkcs11_unlock();
return rv;
}
CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pPart, /* the data (digest) to be signed */
CK_ULONG ulPartLen)
{ /* count of bytes to be signed */
CK_RV
C_SignUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pPart, /* the data (digest) to be signed */
CK_ULONG ulPartLen) /* count of bytes to be signed */
{
CK_RV rv;
struct sc_pkcs11_session *session;
@ -652,10 +707,12 @@ CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
return rv;
}
CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pSignature, /* receives the signature */
CK_ULONG_PTR pulSignatureLen)
{ /* receives byte count of signature */
CK_RV
C_SignFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pSignature, /* receives the signature */
CK_ULONG_PTR pulSignatureLen) /* receives byte count of signature */
{
struct sc_pkcs11_session *session;
CK_ULONG length;
CK_RV rv;
@ -683,15 +740,18 @@ CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen);
}
out: sc_log(context, "C_SignFinal() = %s", lookup_enum ( RV_T, rv ));
out:
sc_log(context, "C_SignFinal() = %s", lookup_enum ( RV_T, rv ));
sc_pkcs11_unlock();
return rv;
}
CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
CK_OBJECT_HANDLE hKey)
{ /* handle of the signature key */
CK_RV
C_SignRecoverInit(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
CK_OBJECT_HANDLE hKey) /* handle of the signature key */
{
CK_RV rv;
CK_BBOOL can_sign;
CK_KEY_TYPE key_type;
@ -739,27 +799,33 @@ CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession, /* the session's handle */
rv = sc_pkcs11_sign_init(session, pMechanism, object, key_type);
out: sc_log(context, "C_SignRecoverInit() = %sn", lookup_enum ( RV_T, rv ));
out:
sc_log(context, "C_SignRecoverInit() = %sn", lookup_enum ( RV_T, rv ));
sc_pkcs11_unlock();
return rv;
}
CK_RV C_SignRecover(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pData, /* the data (digest) to be signed */
CK_ULONG ulDataLen, /* count of bytes to be signed */
CK_BYTE_PTR pSignature, /* receives the signature */
CK_ULONG_PTR pulSignatureLen)
{ /* receives byte count of signature */
CK_RV
C_SignRecover(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pData, /* the data (digest) to be signed */
CK_ULONG ulDataLen, /* count of bytes to be signed */
CK_BYTE_PTR pSignature, /* receives the signature */
CK_ULONG_PTR pulSignatureLen) /* receives byte count of signature */
{
return CKR_FUNCTION_NOT_SUPPORTED;
}
CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
CK_OBJECT_HANDLE hKey)
{ /* handle of encryption key */
CK_RV
C_EncryptInit(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
CK_OBJECT_HANDLE hKey) /* handle of encryption key */
{
return CKR_FUNCTION_NOT_SUPPORTED;
}
CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pData, /* the plaintext data */
CK_ULONG ulDataLen, /* bytes of plaintext data */
@ -789,13 +855,14 @@ CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
CK_OBJECT_HANDLE hKey)
{ /* handle of the decryption key */
CK_RV rv;
CK_BBOOL can_decrypt;
CK_BBOOL can_decrypt, can_unwrap;
CK_KEY_TYPE key_type;
CK_ATTRIBUTE decrypt_attribute = { CKA_DECRYPT, &can_decrypt, sizeof(can_decrypt) };
CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
CK_ATTRIBUTE decrypt_attribute = { CKA_DECRYPT, &can_decrypt, sizeof(can_decrypt) };
CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
CK_ATTRIBUTE unwrap_attribute = { CKA_UNWRAP, &can_unwrap, sizeof(can_unwrap) };
struct sc_pkcs11_session *session;
struct sc_pkcs11_object *object;
CK_RV rv;
if (pMechanism == NULL_PTR)
return CKR_ARGUMENTS_BAD;
@ -818,8 +885,12 @@ CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, /* the session's handle */
rv = object->ops->get_attribute(session, object, &decrypt_attribute);
if (rv != CKR_OK || !can_decrypt) {
rv = CKR_KEY_TYPE_INCONSISTENT;
goto out;
/* Also accept UNWRAP - apps call Decrypt when they mean Unwrap */
rv = object->ops->get_attribute(session, object, &unwrap_attribute);
if (rv != CKR_OK || !can_unwrap) {
rv = CKR_KEY_TYPE_INCONSISTENT;
goto out;
}
}
rv = object->ops->get_attribute(session, object, &key_type_attr);
if (rv != CKR_OK) {
@ -953,21 +1024,20 @@ CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, /* the session's handle */
}
slot = session->slot;
if (slot->card->framework->gen_keypair == NULL) {
if (slot->card->framework->gen_keypair == NULL)
rv = CKR_FUNCTION_NOT_SUPPORTED;
} else {
rv = slot->card->framework->gen_keypair(slot,
pMechanism, pPublicKeyTemplate,
ulPublicKeyAttributeCount,
pPrivateKeyTemplate,
ulPrivateKeyAttributeCount, phPublicKey,
phPrivateKey);
}
else
rv = slot->card->framework->gen_keypair(slot, pMechanism,
pPublicKeyTemplate, ulPublicKeyAttributeCount,
pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
phPublicKey, phPrivateKey);
out: sc_pkcs11_unlock();
out:
sc_pkcs11_unlock();
return rv;
}
CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
CK_OBJECT_HANDLE hWrappingKey, /* handle of the wrapping key */
@ -995,10 +1065,78 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hBaseKey, /* handle of the base key */
CK_ATTRIBUTE_PTR pTemplate, /* template for the new key */
CK_ULONG ulAttributeCount, /* # of attributes in template */
CK_OBJECT_HANDLE_PTR phKey)
{ /* gets handle of derived key */
CK_OBJECT_HANDLE_PTR phKey) /* gets handle of derived key */
{
/* TODO: -DEE ECDH with Cofactor on PIV is an example */
return CKR_FUNCTION_NOT_SUPPORTED;
/* TODO: need to do a lot of checking, will only support ECDH for now.*/
CK_RV rv;
CK_BBOOL can_derive;
CK_KEY_TYPE key_type;
CK_ATTRIBUTE derive_attribute = { CKA_DERIVE, &can_derive, sizeof(can_derive) };
CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
struct sc_pkcs11_session *session;
struct sc_pkcs11_object *object;
struct sc_pkcs11_object *key_object;
if (pMechanism == NULL_PTR)
return CKR_ARGUMENTS_BAD;
rv = sc_pkcs11_lock();
if (rv != CKR_OK)
return rv;
rv = get_object_from_session(hSession, hBaseKey, &session, &object);
if (rv != CKR_OK) {
if (rv == CKR_OBJECT_HANDLE_INVALID)
rv = CKR_KEY_HANDLE_INVALID;
goto out;
}
if (object->ops->derive == NULL_PTR) {
rv = CKR_KEY_TYPE_INCONSISTENT;
goto out;
}
rv = object->ops->get_attribute(session, object, &derive_attribute);
if (rv != CKR_OK || !can_derive) {
rv = CKR_KEY_TYPE_INCONSISTENT;
goto out;
}
rv = object->ops->get_attribute(session, object, &key_type_attr);
if (rv != CKR_OK) {
rv = CKR_KEY_TYPE_INCONSISTENT;
goto out;
}
/* TODO DEE Should also check SENSITIVE, ALWAYS_SENSITIVE, EXTRACTABLE,
NEVER_EXTRACTABLE of the BaseKey against the template for the newkey.
*/
switch(key_type) {
case CKK_EC:
rv = sc_create_object_int(hSession, pTemplate, ulAttributeCount, phKey, 0);
if (rv != CKR_OK)
goto out;
rv = get_object_from_session(hSession, *phKey, &session, &key_object);
if (rv != CKR_OK) {
if (rv == CKR_OBJECT_HANDLE_INVALID)
rv = CKR_KEY_HANDLE_INVALID;
goto out;
}
rv = sc_pkcs11_deri(session, pMechanism, object, key_type,
hSession, *phKey, key_object);
/* TODO if (rv != CK_OK) need to destroy the object */
break;
default:
rv = CKR_KEY_TYPE_INCONSISTENT;
}
out:
sc_pkcs11_unlock();
return rv;
}
CK_RV C_SeedRandom(CK_SESSION_HANDLE hSession, /* the session's handle */

View File

@ -721,6 +721,17 @@ struct ck_mechanism_info
/* Flags for C_WaitForSlotEvent. */
#define CKF_DONT_BLOCK (1UL)
/* Flags for Key derivation */
#define CKD_NULL (1UL << 0)
typedef struct CK_ECDH1_DERIVE_PARAMS {
unsigned long kdf;
unsigned long ulSharedDataLen;
unsigned char * pSharedData;
unsigned long ulPublicDataLen;
unsigned char * pPublicData;
} CK_ECDH1_DERIVE_PARAMS;
typedef unsigned long ck_rv_t;

View File

@ -248,6 +248,18 @@ struct sc_pkcs15init_dataargs {
struct sc_pkcs15_der der_encoded; /* Wrong name: is not DER encoded */
};
struct sc_pkcs15init_skeyargs {
struct sc_pkcs15_id id;
struct sc_pkcs15_id auth_id;
const char * label;
unsigned long usage;
unsigned int flags;
unsigned int access_flags;
unsigned long value_len; /* User requested length */
struct sc_pkcs15_der data_value; /* Wrong name: is not DER encoded */
};
struct sc_pkcs15init_certargs {
struct sc_pkcs15_id id;
const char * label;