From 9c5dbea8838904cfa700d502e4ecbf8d834418e8 Mon Sep 17 00:00:00 2001 From: Viktor Tarasov Date: Sat, 26 May 2012 21:17:39 +0200 Subject: [PATCH] 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). --- src/libopensc/pkcs15.h | 21 ++ src/pkcs11/Makefile.mak | 2 +- src/pkcs11/framework-pkcs15.c | 679 +++++++++++++++++++++++++++++++--- src/pkcs11/mechanism.c | 254 +++++++++---- src/pkcs11/misc.c | 6 +- src/pkcs11/pkcs11-object.c | 418 ++++++++++++++------- src/pkcs11/pkcs11.h | 11 + src/pkcs15init/pkcs15-init.h | 12 + 8 files changed, 1147 insertions(+), 256 deletions(-) diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index f7f6aa92..f3dd8eb1 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -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 diff --git a/src/pkcs11/Makefile.mak b/src/pkcs11/Makefile.mak index b534f8ba..34e55251 100644 --- a/src/pkcs11/Makefile.mak +++ b/src/pkcs11/Makefile.mak @@ -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 diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index de26c560..5a29fdcf 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -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;iialgo_refs[ii];ii++) { + /* Look for algorithm supported by token referenced in the list of key's algorithms */ + for (jj=0;jjreference; 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); diff --git a/src/pkcs11/mechanism.c b/src/pkcs11/mechanism.c index 469e9cb8..e848baf1 100644 --- a/src/pkcs11/mechanism.c +++ b/src/pkcs11/mechanism.c @@ -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; diff --git a/src/pkcs11/misc.c b/src/pkcs11/misc.c index e43be141..81b5dd57 100644 --- a/src/pkcs11/misc.c +++ b/src/pkcs11/misc.c @@ -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; diff --git a/src/pkcs11/pkcs11-object.c b/src/pkcs11/pkcs11-object.c index d1acd368..d89c8111 100644 --- a/src/pkcs11/pkcs11-object.c +++ b/src/pkcs11/pkcs11-object.c @@ -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 */ diff --git a/src/pkcs11/pkcs11.h b/src/pkcs11/pkcs11.h index 55b24ada..1a51a31e 100644 --- a/src/pkcs11/pkcs11.h +++ b/src/pkcs11/pkcs11.h @@ -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; diff --git a/src/pkcs15init/pkcs15-init.h b/src/pkcs15init/pkcs15-init.h index 3286cc81..78e71bcb 100644 --- a/src/pkcs15init/pkcs15-init.h +++ b/src/pkcs15init/pkcs15-init.h @@ -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;