summaryrefslogtreecommitdiff
path: root/p11-capi-key.c
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2008-12-09 20:59:55 +0000
committerStef Walter <stef@memberwebs.com>2008-12-09 20:59:55 +0000
commitae56e5c788e3ed6c60d98d445574d3042aaae24f (patch)
tree9b3acb30fbdfd9e791c81dafb895fd92b396ebfd /p11-capi-key.c
parent398b05acabebf6d882c0aaa94a4dfd3f5d6431d4 (diff)
Move into module folder
Diffstat (limited to 'p11-capi-key.c')
-rw-r--r--p11-capi-key.c1083
1 files changed, 0 insertions, 1083 deletions
diff --git a/p11-capi-key.c b/p11-capi-key.c
deleted file mode 100644
index ed306d4..0000000
--- a/p11-capi-key.c
+++ /dev/null
@@ -1,1083 +0,0 @@
-/*
- * Copyright (C) 2008 Stef Walter
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "p11-capi.h"
-#include "p11-capi-cert.h"
-#include "p11-capi-key.h"
-#include "p11-capi-object.h"
-#include "p11-capi-session.h"
-#include "p11-capi-token.h"
-#include "x509-usages.h"
-
-typedef struct _KeyObject
-{
- P11cObject obj;
-
- /* The raw key identifier */
- CRYPT_HASH_BLOB key_identifier;
- CK_OBJECT_CLASS object_class;
-}
-KeyObject;
-
-typedef struct _KeyObjectData
-{
- P11cObjectData base;
- CK_OBJECT_CLASS object_class;
- CRYPT_INTEGER_BLOB key_identifier;
- CRYPT_DATA_BLOB raw_public_key;
- CRYPT_KEY_PROV_INFO* prov_info;
-}
-KeyObjectData;
-
-static CK_RV
-load_key_handle(P11cObjectData* objdata, HCRYPTPROV* ret_prov,
- HCRYPTKEY* ret_key)
-{
- KeyObjectData* kdata = (KeyObjectData*)objdata;
- HCRYPTPROV prov;
- HCRYPTKEY key;
- DWORD error;
-
- ASSERT(kdata);
- ASSERT(ret_key);
- ASSERT(ret_prov);
-
- if(!CryptAcquireContextW(&prov, kdata->prov_info->pwszContainerName,
- kdata->prov_info->pwszProvName,
- kdata->prov_info->dwProvType, 0))
- {
- return p11c_winerr_to_ckr(GetLastError());
- }
-
- if(!CryptGetUserKey(prov, kdata->prov_info->dwKeySpec, &key))
- {
- error = GetLastError();
- CryptReleaseContext(prov, 0);
- return p11c_winerr_to_ckr(error);
- }
-
- *ret_key = key;
- *ret_prov = prov;
-
- return CKR_OK;
-}
-
-
-static CK_RV
-load_raw_public_key(KeyObjectData* kdata)
-{
- BOOL success = FALSE;
- HCRYPTPROV prov;
- HCRYPTKEY key;
- CK_RV ret;
- DWORD error;
-
- ASSERT(kdata);
- ASSERT(!kdata->raw_public_key.pbData);
-
- ret = load_key_handle(&kdata->base, &prov, &key);
- if(ret != CKR_OK)
- return ret;
-
- if(CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &kdata->raw_public_key.cbData))
- {
- kdata->raw_public_key.pbData = malloc(kdata->raw_public_key.cbData);
- if(!kdata->raw_public_key.pbData)
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- else
- {
- if(CryptExportKey(key, 0, PUBLICKEYBLOB, 0, kdata->raw_public_key.pbData,
- &kdata->raw_public_key.cbData))
- {
- success = TRUE;
- }
- }
- }
-
- CryptReleaseContext(prov, 0);
- CryptDestroyKey(key);
-
- if(success)
- {
- return CKR_OK;
- }
- else
- {
- error = GetLastError();
- if(error == NTE_BAD_KEY_STATE)
- return CKR_ATTRIBUTE_SENSITIVE;
- return p11c_winerr_to_ckr(error);
- }
-}
-
-static CK_RV
-lookup_rsa_attribute(KeyObjectData* kdata, CK_ATTRIBUTE_PTR attr)
-{
- PUBLICKEYSTRUC* header;
- RSAPUBKEY* pubkey;
- CK_ULONG number;
- CK_RV ret;
-
- ASSERT(kdata);
- ASSERT(attr);
-
- if(!kdata->raw_public_key.pbData)
- {
- ret = load_raw_public_key(kdata);
- if(ret != CKR_OK)
- return ret;
- }
-
- header = (PUBLICKEYSTRUC*)kdata->raw_public_key.pbData;
- if(!header->bType == PUBLICKEYBLOB)
- return CKR_GENERAL_ERROR;
-
- pubkey = (RSAPUBKEY*)(header + 1);
- if(!pubkey->magic == 0x31415352)
- return CKR_GENERAL_ERROR;
-
- switch(attr->type)
- {
- case CKA_MODULUS_BITS:
- number = pubkey->bitlen;
- return p11c_return_data(attr, &number, sizeof(CK_ULONG));
-
- case CKA_PUBLIC_EXPONENT:
- return p11c_return_dword_as_bytes(attr, pubkey->pubexp);
-
- case CKA_MODULUS:
- return p11c_return_reversed_data(attr, (pubkey + 1),
- pubkey->bitlen / 8);
-
- case CKA_PRIVATE_EXPONENT:
- case CKA_PRIME_1:
- case CKA_PRIME_2:
- case CKA_EXPONENT_1:
- case CKA_EXPONENT_2:
- case CKA_COEFFICIENT:
- if(kdata->object_class == CKO_PRIVATE_KEY)
- return CKR_ATTRIBUTE_SENSITIVE;
- else
- return CKR_ATTRIBUTE_TYPE_INVALID;
-
- default:
- ASSERT(FALSE);
- return CKR_ATTRIBUTE_TYPE_INVALID;
- }
-}
-
-static CK_RV
-key_bool_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
-{
- KeyObjectData* kdata = (KeyObjectData*)objdata;
- CK_BBOOL val;
- CK_BBOOL is_private, is_rsa;
-
- ASSERT(objdata);
- ASSERT(attr);
-
- is_private = (kdata->object_class == CKO_PRIVATE_KEY);
- is_rsa = kdata->prov_info->dwProvType == PROV_RSA_FULL;
-
- switch(attr->type)
- {
-
- /*
- * Whether to authenticate before every use.
- * - CAPI does all authentication
- */
- case CKA_ALWAYS_AUTHENTICATE:
- val = CK_FALSE;
- break;
-
- /*
- * Whether this key has always been sensitive.
- * TODO: Can we detect this?
- */
- case CKA_ALWAYS_SENSITIVE:
- val = CK_FALSE;
- break;
-
- /*
- * Whether this key can be used to decrypt.
- * - CKK_RSA but not CKK_DSA.
- */
- case CKA_DECRYPT:
- val = is_private && is_rsa;
- break;
-
- /*
- * Whether this key can be used to derive a session or
- * other key.
- * - Not true for CKK_RSA or CKK_DSA.
- */
- case CKA_DERIVE:
- val = CK_FALSE;
- break;
-
- /*
- * Whether or not this key can be used to encrypt?.
- * TODO: Support for RSA public keys.
- */
- case CKA_ENCRYPT:
- val = CK_FALSE;
- break;
-
- /*
- * Whether this key can be exported or not.
- * TODO: We may want to support this for public keys.
- */
- case CKA_EXTRACTABLE:
- val = CK_FALSE;
- break;
-
- /*
- * Whether this key was created on token.
- * TODO: Can we implement this properly?
- */
- case CKA_LOCAL:
- val = CK_FALSE;
- break;
-
- /*
- * Whether this object is modifiable.
- * - Keys are generally. never modifiable.
- */
- case CKA_MODIFIABLE:
- val = CK_FALSE;
- break;
-
- /*
- * Whether this key was ever extractable.
- * TODO: Can we determine this?
- */
- case CKA_NEVER_EXTRACTABLE:
- val = CK_FALSE;
- break;
-
- /*
- * Whether this is a private object or not.
- * - This 'private' means login before use. But maps
- * well to private key use, since we're always logged in.
- */
- case CKA_PRIVATE:
- val = is_private;
- break;
-
- /*
- * Whether this is a sensitive object or not.
- * - Private keys are sensitive, some attributes not
- * readable.
- */
- case CKA_SENSITIVE:
- val = is_private;
- break;
-
- /*
- * Can this key sign stuff?
- * - Private keys can sign.
- */
- case CKA_SIGN:
- val = is_private;
- break;
-
- /*
- * Can this key sign recoverable.
- * TODO: Private RSA keys can sign recoverable.
- */
- case CKA_SIGN_RECOVER:
- val = CK_FALSE;
- break;
-
- /*
- * Is this stored on the token?
- * - All CAPI objects are.
- */
- case CKA_TOKEN:
- val = CK_TRUE;
- break;
-
- /*
- * Is this key trusted?
- * - A nebulous question.
- */
- case CKA_TRUSTED:
- val = CK_FALSE;
- break;
-
- /*
- * Key wrapping with public keys.
- */
- case CKA_WRAP:
- if(is_private)
- return CKR_ATTRIBUTE_TYPE_INVALID;
- val = CK_FALSE;
- break;
-
- /*
- * Key wrapping on private keys.
- */
- case CKA_WRAP_WITH_TRUSTED:
- if(!is_private)
- return CKR_ATTRIBUTE_TYPE_INVALID;
- val = CK_FALSE;
- break;
-
- /*
- * Can do a unwrap operation?
- * - We don't implement this.
- */
- case CKA_UNWRAP:
- val = CK_FALSE;
- break;
-
- /*
- * Wrap, and unwrap stuff.
- * - We don't implement this.
- */
- case CKA_UNWRAP_TEMPLATE:
- return CKR_ATTRIBUTE_TYPE_INVALID;
-
- /*
- * Whether this key can be used to verify?
- * TODO: Support for public keys.
- */
- case CKA_VERIFY:
- val = CK_FALSE;
- break;
-
- /*
- * Whether this key can be used to verify?
- * TODO: Support for public keys.
- */
- case CKA_VERIFY_RECOVER:
- val = CK_FALSE;
- break;
-
- default:
- return CKR_ATTRIBUTE_TYPE_INVALID;
- };
-
- return p11c_return_data(attr, &val, sizeof(CK_BBOOL));
-}
-
-static CK_RV
-key_ulong_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
-{
- KeyObjectData* kdata = (KeyObjectData*)objdata;
- CK_ULONG val;
-
- ASSERT(kdata);
- ASSERT(attr);
-
- switch(attr->type)
- {
-
- /*
- * Object class.
- */
- case CKA_CLASS:
- val = kdata->object_class;
- break;
-
- /*
- * The key type.
- * - Right now we only support (and load) RSA.
- */
- case CKA_KEY_TYPE:
- if(kdata->prov_info->dwProvType == PROV_RSA_FULL)
- val = CKK_RSA;
- else
- val = CK_UNAVAILABLE_INFORMATION;
- break;
-
- /*
- * The key generation mechanism.
- * TODO: We don't yet support key generation.
- */
- case CKA_KEY_GEN_MECHANISM:
- val = CK_UNAVAILABLE_INFORMATION;
- break;
-
- /*
- * The RSA modulus bits.
- */
- case CKA_MODULUS_BITS:
- if(kdata->prov_info->dwProvType == PROV_RSA_FULL)
- return lookup_rsa_attribute(kdata, attr);
- else
- return CKR_ATTRIBUTE_TYPE_INVALID;
-
- default:
- return CKR_ATTRIBUTE_TYPE_INVALID;
- };
-
- return p11c_return_data(attr, &val, sizeof(CK_ULONG));
-}
-
-static CK_RV
-key_bytes_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
-{
- KeyObjectData* kdata = (KeyObjectData*)objdata;
- CK_MECHANISM_TYPE allowed_mechanisms[] = { CKM_RSA_PKCS };
- WCHAR* label;
-
- ASSERT(kdata);
- ASSERT(attr);
-
- switch(attr->type)
- {
- /*
- * The ID of the key. This should match the ID we
- * return for any matching certificates.
- */
- case CKA_ID:
- return p11c_return_data(attr, kdata->key_identifier.pbData,
- kdata->key_identifier.cbData);
-
- /*
- * The key label.
- * - We use the container name.
- */
- case CKA_LABEL:
- label = kdata->prov_info->pwszContainerName;
- if(!label)
- label = L"Unnamed Key";
- return p11c_return_string(attr, label);
-
- /*
- * The subject of the related certificate.
- * TODO: Implement this lookup.
- */
- case CKA_SUBJECT:
- return p11c_return_data(attr, "", 0);
-
- /*
- * Allowed mechanisms with this key.
- * - RSA used with CKM_RSA
- * TODO: Needs updating when DSA implemented.
- */
- case CKA_ALLOWED_MECHANISMS:
- return p11c_return_data(attr, &allowed_mechanisms,
- sizeof(allowed_mechanisms));
-
- /*
- * Various RSA public attributes.
- */
- case CKA_MODULUS:
- case CKA_PUBLIC_EXPONENT:
- case CKA_PRIVATE_EXPONENT:
- case CKA_PRIME_1:
- case CKA_PRIME_2:
- case CKA_EXPONENT_1:
- case CKA_EXPONENT_2:
- case CKA_COEFFICIENT:
- if(kdata->prov_info->dwProvType == PROV_RSA_FULL)
- return lookup_rsa_attribute(kdata, attr);
- else
- return CKR_ATTRIBUTE_TYPE_INVALID;
-
- /*
- * Last date this key can be used.
- * TODO: Does CAPI support this ability?
- */
- case CKA_END_DATE:
- case CKA_START_DATE:
- return p11c_return_data(attr, "", 0);
-
- default:
- return CKR_ATTRIBUTE_TYPE_INVALID;
- };
-}
-
-static void
-key_release(void* data)
-{
- KeyObjectData* kdata = (KeyObjectData*)data;
- ASSERT(kdata);
-
- ASSERT(kdata->key_identifier.pbData);
- ASSERT(kdata->prov_info);
-
- free(kdata->key_identifier.pbData);
- free(kdata->prov_info);
-
- free(kdata);
-}
-
-static const P11cObjectDataVtable key_objdata_vtable = {
- key_bool_attribute,
- key_ulong_attribute,
- key_bytes_attribute,
- key_release,
-};
-
-static CRYPT_KEY_PROV_INFO*
-duplicate_prov_info(CRYPT_KEY_PROV_INFO* original)
-{
- DWORD container_length, prov_length;
- CRYPT_KEY_PROV_INFO* result;
- DWORD length, i;
- BYTE* at;
- BYTE* end;
-
- if(!original)
- return NULL;
-
- /* Go through and calculate the length */
- length = sizeof(CRYPT_KEY_PROV_INFO);
- if(original->pwszContainerName)
- {
- container_length = (wcslen(original->pwszContainerName) + 1) * sizeof(WCHAR);
- length += container_length;
- }
-
- if(original->pwszProvName)
- {
- prov_length = (wcslen(original->pwszProvName) + 1) * sizeof(WCHAR);
- length += prov_length;
- }
-
- length += sizeof(CRYPT_KEY_PROV_PARAM) * original->cProvParam;
- for(i = 0; i < original->cProvParam; ++i)
- length += original->rgProvParam[i].cbData;
-
- /* Allocate a single block of memory for everything */
- at = (BYTE*)malloc(length);
- if(!at)
- {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return NULL;
- }
-
- /* Copy in very carefully */
- end = at + length;
-
- memcpy(at, original, sizeof(CRYPT_KEY_PROV_INFO));
- result = (CRYPT_KEY_PROV_INFO*)at;
- at += sizeof(CRYPT_KEY_PROV_INFO);
-
- if(result->pwszContainerName)
- {
- memcpy(at, result->pwszContainerName, container_length);
- result->pwszContainerName = (LPWSTR)at;
- at += container_length;
- }
-
- if(result->pwszProvName)
- {
- memcpy(at, result->pwszProvName, prov_length);
- result->pwszProvName = (LPWSTR)at;
- at += prov_length;
- }
-
- if(original->cProvParam)
- {
- memcpy(at, result->rgProvParam, sizeof(CRYPT_KEY_PROV_PARAM) * result->cProvParam);
- result->rgProvParam = (CRYPT_KEY_PROV_PARAM*)at;
- at += sizeof(CRYPT_KEY_PROV_PARAM) * result->cProvParam;
-
- for(i = 0; i < result->cProvParam; ++i)
- {
- memcpy(at, result->rgProvParam[i].pbData, result->rgProvParam[i].cbData);
- result->rgProvParam[i].pbData = (BYTE*)at;
- at += result->rgProvParam[i].cbData;
- }
- }
-
- ASSERT(at == end);
- return result;
-}
-
-static P11cObjectData*
-key_alloc_data(P11cSession* sess, P11cObject* obj, CRYPT_KEY_PROV_INFO* prov_info)
-{
- KeyObject* kobj = (KeyObject*)obj;
- KeyObjectData* kdata;
-
- kdata = (KeyObjectData*)calloc(1, sizeof(KeyObjectData));
- if(!kdata)
- return NULL;
-
- /* Allocate memory for key identifier */
- kdata->key_identifier.pbData = malloc(kobj->key_identifier.cbData);
- if(!kdata->key_identifier.pbData)
- {
- free(kdata);
- return NULL;
- }
-
- /* Setup the object data */
- kdata->object_class = kobj->object_class;
- kdata->prov_info = prov_info;
- kdata->key_identifier.cbData = kobj->key_identifier.cbData;
- memcpy(kdata->key_identifier.pbData, kobj->key_identifier.pbData,
- kdata->key_identifier.cbData);
- kdata->raw_public_key.pbData = NULL;
- kdata->raw_public_key.cbData = 0;
-
- kdata->base.object = obj->id;
- kdata->base.data_funcs = &key_objdata_vtable;
-
- return &(kdata->base);
-}
-
-static BOOL WINAPI
-load_key_property_info(PCRYPT_HASH_BLOB key_identifier, DWORD flags,
- void* reserved, void* arg, DWORD n_props, DWORD* props,
- void** datas, DWORD* n_datas)
-{
- CRYPT_KEY_PROV_INFO** prov_info = (CRYPT_KEY_PROV_INFO**)arg;
- DWORD i;
-
- /*
- * Already got a provider info. This shouldn't happen
- * but can occur if the same key is present twice.
- */
- if(*prov_info)
- return TRUE;
-
- /* Find the key provider info property */
- for(i = 0; i < n_props; ++i)
- {
- if(props[i] == CERT_KEY_PROV_INFO_PROP_ID)
- {
- *prov_info = duplicate_prov_info((CRYPT_KEY_PROV_INFO*)datas[i]);
- break;
- }
- }
-
- return TRUE;
-}
-
-static CK_RV
-key_load_data(P11cSession* sess, P11cObject* obj, P11cObjectData** objdata)
-{
- KeyObject* kobj = (KeyObject*)obj;
- CRYPT_KEY_PROV_INFO* prov_info = NULL;
-
- ASSERT(kobj);
- ASSERT(objdata);
-
- /* Load the provider info */
- if(!CryptEnumKeyIdentifierProperties((CRYPT_HASH_BLOB*)&kobj->key_identifier,
- CERT_KEY_PROV_INFO_PROP_ID, 0, NULL, NULL,
- &prov_info, load_key_property_info))
- return p11c_winerr_to_ckr(GetLastError());
-
- /* No provider info, bad news */
- if(!prov_info)
- return CKR_GENERAL_ERROR;
-
- *objdata = key_alloc_data(sess, obj, prov_info);
- if(!(*objdata))
- {
- free(prov_info);
- return CKR_HOST_MEMORY;
- }
-
- return CKR_OK;
-}
-
-static unsigned int
-key_hash_func(P11cObject* obj)
-{
- KeyObject* kobj = (KeyObject*)obj;
- return p11c_hash_data(kobj->key_identifier.pbData, kobj->key_identifier.cbData) ^
- p11c_hash_integer((int)kobj->object_class);
-}
-
-static int
-key_equal_func(P11cObject* a, P11cObject* b)
-{
- KeyObject* ka = (KeyObject*)a;
- KeyObject* kb = (KeyObject*)b;
- return ka->object_class == kb->object_class &&
- ka->key_identifier.cbData == kb->key_identifier.cbData &&
- memcmp(ka->key_identifier.pbData, kb->key_identifier.pbData, ka->key_identifier.cbData) == 0;
-}
-
-static void
-key_object_release(void* data)
-{
- KeyObject* kobj = (KeyObject*)data;
- ASSERT(kobj);
- free(kobj);
-}
-
-static const P11cObjectVtable key_object_vtable = {
- key_load_data,
- key_hash_func,
- key_equal_func,
- key_object_release,
-};
-
-static CK_RV
-register_key_object(P11cSession* sess, CK_OBJECT_CLASS cls,
- CRYPT_HASH_BLOB* key_identifier, P11cObject** obj)
-{
- KeyObject* kobj;
- CK_RV ret;
-
- ASSERT(obj);
- ASSERT(key_identifier);
- ASSERT(cls == CKO_PRIVATE_KEY || cls == CKO_PUBLIC_KEY);
-
- kobj = calloc(1, sizeof(KeyObject) + key_identifier->cbData);
- if(!kobj)
- return CKR_HOST_MEMORY;
-
- kobj->obj.id = 0;
- kobj->obj.obj_funcs = &key_object_vtable;
-
- kobj->object_class = cls;
- kobj->key_identifier.pbData = (BYTE*)(kobj + 1);
- kobj->key_identifier.cbData = key_identifier->cbData;
- memcpy(kobj->key_identifier.pbData, key_identifier->pbData,
- kobj->key_identifier.cbData);
-
- ret = p11c_token_register_object(sess->slot, &(kobj->obj));
- if(ret != CKR_OK)
- {
- free(kobj);
- return ret;
- }
-
- ASSERT(kobj->obj.id != 0);
- *obj = &(kobj->obj);
-
- return CKR_OK;
-}
-
-typedef struct _EnumArguments
-{
- P11cSession* sess;
- CK_OBJECT_CLASS object_class;
- CK_ATTRIBUTE_PTR match;
- CK_ULONG count;
- P11cArray* results;
- CK_RV ret;
-}
-EnumArguments;
-
-static BOOL WINAPI
-enum_key_property_info(PCRYPT_HASH_BLOB key_identifier, DWORD flags,
- void* reserved, void* arg, DWORD n_props, DWORD* props,
- void** datas, DWORD* n_datas)
-{
- EnumArguments* args = (EnumArguments*)arg;
- CRYPT_KEY_PROV_INFO* prov_info = NULL;
- P11cObject *obj = NULL;
- KeyObjectData kdata;
- DWORD i;
-
- /* Find the key provider info property */
- for(i = 0; i < n_props; ++i)
- {
- if(props[i] == CERT_KEY_PROV_INFO_PROP_ID)
- {
- prov_info = (CRYPT_KEY_PROV_INFO*)datas[i];
- break;
- }
- }
-
- /* Strange key, skip */
- if(!prov_info)
- return TRUE;
-
- /* Match the public key */
- kdata.prov_info = prov_info;
- kdata.object_class = args->object_class;
- kdata.base.object = 0;
- kdata.base.data_funcs = &key_objdata_vtable;
-
- if(p11c_object_data_match(&kdata.base, args->match, args->count))
- {
- args->ret = register_key_object(args->sess, args->object_class, key_identifier, &obj);
- if(args->ret == CKR_OK)
- {
- ASSERT(obj);
- p11c_array_append(args->results, obj->id);
- }
- }
-
- return TRUE;
-
-}
-
-static CK_RV
-find_any_keys(P11cSession* sess, CK_OBJECT_CLASS cls,
- CK_ATTRIBUTE_PTR match, CK_ULONG count, P11cArray* arr)
-{
- CRYPT_HASH_BLOB find_id;
- EnumArguments enum_args;
- CK_ULONG i;
-
- /* Try to setup for an efficient search based on key id */
- memset(&find_id, 0, sizeof(find_id));
- for(i = 0; i < count; ++i)
- {
- if(!match[i].pValue || !match[i].ulValueLen)
- continue;
- if(match[i].type == CKA_ID)
- {
- find_id.cbData = match[i].ulValueLen;
- find_id.pbData = match[i].pValue;
- }
- }
-
- enum_args.sess = sess;
- enum_args.match = match;
- enum_args.count = count;
- enum_args.results = arr;
- enum_args.object_class = cls;
- enum_args.ret = CKR_OK;
-
- if(!CryptEnumKeyIdentifierProperties(find_id.cbData != 0 ? &find_id : NULL,
- CERT_KEY_PROV_INFO_PROP_ID, 0, NULL, NULL,
- &enum_args, enum_key_property_info))
- return p11c_winerr_to_ckr(GetLastError());
-
- return enum_args.ret;
-}
-
-static CK_RV
-list_matching_certificates(P11cSession* sess, CK_ATTRIBUTE_PTR match,
- CK_ULONG count, P11cArray* arr)
-{
- CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
- CK_ATTRIBUTE search[3];
- CK_ULONG n_search = 0;
- CK_ULONG i;
-
- /* The class */
- search[0].type = CKA_CLASS;
- search[0].pValue = &cert_class;
- search[0].ulValueLen = sizeof(CK_OBJECT_CLASS);
- ++n_search;
-
- for(i = 0; i < count && n_search < 3; ++i)
- {
- /*
- * This is the attributes that tie a certificate
- * to key object, so try match certs with these
- */
- if(match[i].type == CKA_ID)
- {
- search[n_search].type = match[i].type;
- search[n_search].pValue = match[i].pValue;
- search[n_search].ulValueLen = match[i].ulValueLen;
- ++n_search;
- }
- }
-
- /* Do the certificate search */
- return p11c_cert_find(sess, CKO_CERTIFICATE, search, n_search, arr);
-}
-
-static CK_RV
-find_certificate_key(P11cSession* session, CK_OBJECT_CLASS cls,
- CK_ATTRIBUTE_PTR match, CK_ULONG count,
- PCCERT_CONTEXT cert, P11cArray* arr)
-{
- CRYPT_KEY_PROV_INFO* prov_info;
- CRYPT_HASH_BLOB key_identifier;
- P11cObjectData* objdata;
- KeyObjectData kdata;
- P11cObject* obj;
- DWORD prov_length;
- DWORD error;
- CK_RV ret = CKR_OK;
-
- /* Look up the key provider info and identifier */
- if(!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &prov_length) ||
- !CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &key_identifier.cbData))
- {
- error = GetLastError();
- if(error == CRYPT_E_NOT_FOUND)
- return CKR_OK;
- return p11c_winerr_to_ckr(error);
- }
-
- /* We own the info memory */
- prov_info = malloc(prov_length);
- if(!prov_info)
- return CKR_HOST_MEMORY;
- key_identifier.pbData = malloc(key_identifier.cbData);
- if(!key_identifier.pbData)
- {
- free(prov_info);
- return CKR_HOST_MEMORY;
- }
-
- /* Lookup the key provider info and identifier */
- if(CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, prov_info, &prov_length) &&
- CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, key_identifier.pbData, &key_identifier.cbData))
- {
- kdata.object_class = cls;
- kdata.prov_info = prov_info;
- kdata.key_identifier = key_identifier;
- kdata.base.object = 0;
- kdata.base.data_funcs = &key_objdata_vtable;
-
- if(p11c_object_data_match(&kdata.base, match, count))
- {
- ret = register_key_object(session, cls, &key_identifier, &obj);
- if(ret == CKR_OK)
- {
- ASSERT(obj);
-
- /* Store away the object data for performance reasons */
- objdata = key_alloc_data(session, obj, prov_info);
- if(objdata)
- {
- p11c_session_take_object_data(session, obj, objdata);
-
- /* Note these are used, and not to be freed */
- key_identifier.pbData = NULL;
- key_identifier.cbData = 0;
- prov_info = NULL;
- }
-
- p11c_array_append(arr, obj->id);
- }
- }
- }
- else
- {
- ret = p11c_winerr_to_ckr(GetLastError());
- }
-
- if(key_identifier.pbData)
- free(key_identifier.pbData);
- if(prov_info)
- free(prov_info);
-
- return ret;
-}
-
-static CK_RV
-find_certificate_keys(P11cSession* session, CK_OBJECT_CLASS cls,
- CK_ATTRIBUTE_PTR match, CK_ULONG count, P11cArray* arr)
-{
- CK_OBJECT_HANDLE id;
- P11cObjectData* certdata;
- P11cArray* certarr;
- PCCERT_CONTEXT cert;
- CK_RV ret = CKR_OK;
- CK_ULONG i;
-
- /* Get a list of all certificates */
- certarr = p11c_array_new(0, 1, sizeof(CK_OBJECT_HANDLE));
- if(!certarr)
- return CKR_HOST_MEMORY;
- ret = list_matching_certificates(session, match, count, certarr);
-
- /* Now match each of them against our criteria */
- if(ret == CKR_OK)
- {
- for(i = 0; i < certarr->len; ++i)
- {
- id = p11c_array_index(certarr, CK_OBJECT_HANDLE, i);
- ASSERT(id);
-
- /* Get the certificate data for this certificate object */
- if(p11c_session_get_object_data_for(session, id, &certdata) != CKR_OK)
- continue;
-
- /* Get the certificate context */
- cert = p11c_cert_object_data_get_certificate(certdata);
- if(!cert)
- continue;
-
- /* Remember we can have either or both keys for each certificate */
- ret = find_certificate_key(session, cls, match, count, cert, arr);
- }
- }
-
- p11c_array_free(certarr, TRUE);
- return ret;
-}
-
-CK_RV
-p11c_key_find(P11cSession* sess, CK_OBJECT_CLASS cls,
- CK_ATTRIBUTE_PTR match, CK_ULONG count, P11cArray* arr)
-{
- CK_RV ret = CKR_OK;
-
- /* Is this somewhere we have all keys present? */
- if(p11c_token_get_flags(sess->slot) & P11C_SLOT_ANYKEY)
- {
- if((cls == CKO_PRIVATE_KEY || cls == CKO_ANY) && ret == CKR_OK)
- ret = find_any_keys(sess, CKO_PRIVATE_KEY, match, count, arr);
- if((cls == CKO_PUBLIC_KEY || cls == CKO_ANY) && ret == CKR_OK)
- ret = find_any_keys(sess, CKO_PUBLIC_KEY, match, count, arr);
- }
-
- /* Otherwise we can only list the keys that have certificates */
- else
- {
- if((cls == CKO_PRIVATE_KEY || cls == CKO_ANY) && ret == CKR_OK)
- ret = find_certificate_keys(sess, CKO_PRIVATE_KEY, match, count, arr);
- if((cls == CKO_PUBLIC_KEY || cls == CKO_ANY) && ret == CKR_OK)
- ret = find_certificate_keys(sess, CKO_PUBLIC_KEY, match, count, arr);
- }
-
- return ret;
-}
-
-DWORD
-p11c_key_object_data_get_bits(P11cObjectData* objdata)
-{
- KeyObjectData* kdata;
- PUBLICKEYSTRUC* header;
- RSAPUBKEY* pubkey;
- CK_RV ret;
-
- ASSERT(objdata);
-
- kdata = (KeyObjectData*)objdata;
-
- if(!kdata->raw_public_key.pbData)
- {
- ret = load_raw_public_key(kdata);
- if(ret != CKR_OK)
- return ret;
- }
-
- header = (PUBLICKEYSTRUC*)kdata->raw_public_key.pbData;
- if(!header->bType == PUBLICKEYBLOB)
- return 0;
-
- pubkey = (RSAPUBKEY*)(header + 1);
- if(!pubkey->magic == 0x31415352)
- return 0;
-
- return pubkey->bitlen;
-}
-
-CRYPT_KEY_PROV_INFO*
-p11c_key_object_data_get_prov_info(P11cObjectData* objdata)
-{
- KeyObjectData* kdata;
-
- ASSERT(objdata);
- kdata = (KeyObjectData*)objdata;
- return kdata->prov_info;
-}