summaryrefslogtreecommitdiff
path: root/ckcapi-object.c
diff options
context:
space:
mode:
Diffstat (limited to 'ckcapi-object.c')
-rw-r--r--ckcapi-object.c744
1 files changed, 248 insertions, 496 deletions
diff --git a/ckcapi-object.c b/ckcapi-object.c
index 531ad2f..c02c365 100644
--- a/ckcapi-object.c
+++ b/ckcapi-object.c
@@ -1,9 +1,165 @@
-#include "cryptoki-capi.h"
+#include "ckcapi.h"
+
+#include <memory.h>
#include <wtypes.h>
#include <wincrypt.h>
+static CkCapiArray* object_array = NULL;
+static CkCapiHash* object_hash = NULL;
+
+static void
+object_free(CkCapiObject* obj)
+{
+ ASSERT(obj);
+ ASSERT(obj->obj_funcs.release);
+ (obj->obj_funcs.release)(obj);
+}
+
+CkCapiObject*
+ckcapi_object_lookup(CkCapiSession* sess, CK_OBJECT_HANDLE obj)
+{
+ /* This must be called without any locks held */
+
+ CkCapiObject* ret = NULL;
+
+ ASSERT(sess);
+ ASSERT(obj > 0);
+
+ ckcapi_lock_global();
+
+ if(object_array && obj < object_array->len)
+ ret = ckcapi_array_index(object_array, CkCapiObject*, obj);
+
+ ckcapi_unlock_global();
+
+ return ret;
+}
+
+CK_RV
+ckcapi_object_register(CkCapiSession* sess, CkCapiObject* obj)
+{
+ CkCapiObject* prev;
+ CK_RV ret = CKR_OK;
+
+ ASSERT(sess);
+ ASSERT(obj->id == 0);
+ ASSERT(obj->unique_key);
+ ASSERT(obj->unique_len);
+
+ DBGS(sess, "registering new session");
+
+ ckcapi_lock_global();
+
+ if(!object_array)
+ {
+ object_array = ckcapi_array_sized_new(0, 1, sizeof(CkCapiObject*), 16);
+ if(object_array)
+ {
+ /* A blank entry for '0' */
+ CkCapiObject* blank = NULL;
+ ckcapi_array_append(object_array, blank);
+ }
+
+ object_hash = ckcapi_hash_new();
+
+
+ if(!object_array || !object_hash)
+ {
+ /* Allocation failed above */
+ ret = CKR_HOST_MEMORY;
+ }
+ }
+
+ if(ret == CKR_OK)
+ {
+ ASSERT(object_array);
+ ASSERT(object_hash);
+
+ /* Look in the hash and find a previous object */
+ prev = ckcapi_hash_get(object_hash, obj->unique_key, obj->unique_len);
+ if(prev)
+ {
+ /* Register it in the previous object's place */
+ obj->id = prev->id;
+ ASSERT(prev->id < object_array->len);
+ if(ckcapi_hash_set(object_hash, obj->unique_key, obj->unique_len, obj))
+ {
+ ckcapi_array_index(object_array, CkCapiObject*, obj->id) = obj;
+ object_free(prev);
+ DBGO(obj, "found old object id");
+ }
+ else
+ {
+ ret = CKR_HOST_MEMORY;
+ }
+
+ }
+ else
+ {
+ /* Register it at the end of the array */
+ obj->id = object_array->len;
+ ASSERT(obj->id > 0);
+ if(ckcapi_hash_set(object_hash, obj->unique_key, obj->unique_len, obj))
+ {
+ if(ckcapi_array_append(object_array, obj))
+ {
+ DBGO(obj, "registered new object id");
+ }
+ else
+ {
+ ret = CKR_HOST_MEMORY;
+
+ /* Roll back our addition */
+ ckcapi_hash_rem(object_hash, obj->unique_key, obj->unique_len);
+ }
+ }
+ else
+ {
+ ret = CKR_HOST_MEMORY;
+ }
+ }
+ }
+
+ ckcapi_unlock_global();
+
+ return ret;
+
+}
+
+CK_RV
+ckcapi_object_load_data(CkCapiObject* obj, CkCapiObjectData* objdata)
+{
+ ASSERT(obj);
+ ASSERT(obj->id);
+ ASSERT(obj->obj_funcs.load_data);
+
+ memset(objdata, 0, sizeof(*objdata));
+ return (obj->obj_funcs.load_data)(obj, objdata);
+}
+
+void
+ckcapi_object_data_release(CkCapiObjectData* objdata)
+{
+ ASSERT(objdata->data_funcs.release);
+ (objdata->data_funcs.release)(objdata->data);
+ memset(objdata, 0, sizeof(*objdata));
+}
+
+CK_RV
+ckcapi_object_load_data_for(CkCapiSession* sess, CK_OBJECT_HANDLE hand,
+ CkCapiObjectData* objdata)
+{
+ CkCapiObject* obj;
+
+ obj = ckcapi_object_lookup(sess, hand);
+ if(!obj)
+ return CKR_OBJECT_HANDLE_INVALID;
+
+ return ckcapi_object_load_data(obj, objdata);
+}
+
enum
{
DATA_UNKNOWN = 0,
@@ -13,7 +169,6 @@ enum
DATA_BYTES
};
-
int
attribute_data_type(CK_ATTRIBUTE_TYPE type)
{
@@ -27,7 +182,7 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type)
case CKA_MODULUS_BITS:
case CKA_PRIME_BITS:
case CKA_SUBPRIME_BITS:
- case CKA_SUB_PRIME_BITS:
+ /* case CKA_SUB_PRIME_BITS: */
case CKA_VALUE_BITS:
case CKA_VALUE_LEN:
case CKA_KEY_GEN_MECHANISM:
@@ -40,7 +195,7 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type)
case CKA_BITS_PER_PIXEL:
case CKA_MECHANISM_TYPE:
case CKA_JAVA_MIDP_SECURITY_DOMAIN:
- return DATA_ULONG:
+ return DATA_ULONG;
// CK_BBOOL attribute types
case CKA_TOKEN:
@@ -56,7 +211,7 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type)
case CKA_NEVER_EXTRACTABLE:
case CKA_ALWAYS_SENSITIVE:
case CKA_WRAP_WITH_TRUSTED:
- case CKA_ALWAYS_AUTHENTICATE
+ case CKA_ALWAYS_AUTHENTICATE:
case CKA_ENCRYPT:
case CKA_WRAP:
case CKA_VERIFY:
@@ -96,7 +251,7 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type)
case CKA_SUBPRIME:
case CKA_BASE:
case CKA_ECDSA_PARAMS:
- case CKA_EC_PARAMS:
+ /* case CKA_EC_PARAMS: */
case CKA_EC_POINT:
case CKA_CHAR_SETS:
case CKA_ENCODING_METHODS:
@@ -120,536 +275,133 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type)
};
}
-CK_RV
-attribute_fill(CK_ATTRIBUTE_PTR attr, CK_ATTRIBUTE_TYPE type,
- CK_VOID_PTR* val, CK_ULONG len)
+CK_BBOOL
+ckcapi_object_data_match_attr(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR match)
{
- ASSERT(attr);
- ASSERT(val);
- ASSERT(len);
-
- attr->type = type;
+ CK_VOID_PTR value;
+ CK_ULONG len;
+ CK_RV rv;
+ int dtype;
- if(attr->pValue && attr->ulValueLen < len)
- {
- attr->ulValueLen = len;
- return CKR_BUFFER_TOO_SMALL;
- }
-
- else if(!attr->pValue)
- {
- attr->ulValueLen = len;
- return CKR_OK;
- }
+ ASSERT(match);
+ ASSERT(objdata && objdata->data);
- else
- {
- memcpy(attr->pValue, &val, len);
- attr->ulValueLen = len;
- return CKR_OK;
- }
-}
+ /* Get the data type of the attribute */
+ dtype = attribute_data_type(match->type);
+ if(dtype == DATA_UNKNOWN)
+ return CK_FALSE;
-CK_RV
-attribute_match(CK_ATTRIBUTE_PTR attr, CK_ATTRIBUTE_TYPE type,
- CK_VOID_PTR* val, CK_ULONG len)
-{
- ASSERT(attr);
- ASSERT(val);
- ASSERT(len);
-
- if(attr->pValue && attr->ulValueLen == len &&
- memcmp(attr->pValue, &val, len);
- return CKR_OK;
- return CKR_CANCEL;
-}
+ /* We only do byte matching */
+ if(match->pValue == NULL)
+ return CK_FALSE;
-/* --------------------------------------------------------------------------
- * CERTIFICATES
- */
+ /* Only load as much data as is needed */
+ value = _alloca(match->ulValueLen > 4 ? match->ulValueLen : 4);
+ len = match->ulValueLen;
-static CK_RV
-cert_bool_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert,
- CK_ATTRIBUTE_PTR attr, CK_BBOOL fill)
-{
- CK_BBOOL val;
- switch(type)
+ switch(dtype)
{
- /*
- * Resides on the token
- * - Always true for CAPI objects.
- */
- case CKA_TOKEN:
- val = CK_TRUE;
+ case DATA_BOOL:
+ rv = (objdata->data_funcs.get_bool)(objdata->data, match->type, value, &len);
break;
-
- /*
- * Private vs. Public object.
- * - Always false for certificates.
- */
- case CKA_PRIVATE:
- val = CK_FALSE;
+ case DATA_ULONG:
+ rv = (objdata->data_funcs.get_ulong)(objdata->data, match->type, value, &len);
break;
-
- /*
- * If object can be modified.
- * - Currently always false. In the future with additional
- * functionality this may change.
- */
- case CKA_MODIFIABLE:
- val = CK_FALSE;
+ case DATA_BYTES:
+ rv = (objdata->data_funcs.get_bytes)(objdata->data, match->type, value, &len);
break;
-
- /*
- * Whether the certificate can be trusted for the application
- * in which it was created.
- * - Use CertGetCertificateChain to build up a chain
- * for this certificate, and then look in the CERT_CHAIN_CONTEXT
- * TrustStatus field.
- */
- case CKA_TRUSTED:
- /* TODO: Implement */
-
- default:
- return CK_CANCEL;
- };
-
- if(fill)
- return attribute_fill(attr, type, &val, sizeof(CK_BBOOL));
- else
- return attribute_match(attr, type, &val, sizeof(CK_BBOOL));
-}
-
-static CK_RV
-cert_ulong_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert,
- CK_ATTRIBUTE_PTR attr, CK_BBOOL fill)
-{
- CK_ULONG val;
- switch(type)
- {
-
- /*
- * Object class.
- * - Always CKO_CERTIFICATE for certificates.
- */
- case CKA_OBJECT_CLASS:
- val = CKO_CERTIFICATE;
+ case DATA_DATE:
+ rv = (objdata->data_funcs.get_date)(objdata->data, match->type, value, &len);
break;
-
- /*
- * Type of certificate.
- * - Always X509.
- */
- case CKA_CERTIFICATE_TYPE:
- val = CKC_X_509;
- break;
-
- /*
- * Whether a CA, user certificate, other.
- * - Get certificate szOID_ENHANCED_KEY_USAGE
- * extension or CERT_CTL_PROP_ID and look into CTL_USAGE structure.
- */
- case CKA_CERTIFICATE_CATEGORY:
- /* TODO: Implement */
-
default:
- return CK_CANCEL;
- };
-
- if(fill)
- return attribute_fill(attr, type, &val, sizeof(CK_ULONG));
- else
- return attribute_match(attr, type, &val, sizeof(CK_ULONG));
-}
-
-static CK_RV
-cert_bytes_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert,
- CK_ATTRIBUTE_PTR attr, CK_BBOOL fill)
-{
- switch(type)
- {
-
- /*
- * Description of the object.
- * - We use CAPI's CERT_FRIENDLY_NAME_PROP_ID property,
- * converted into UTF8.
- */
- case CKA_LABEL:
- xxxxx
- break;
-
- /*
- * A byte array unique to this certificate. The CKA_ID of
- * matching certificates and private keys should match.
- * Should match the key identifier in an X.509v3 certificate.
- *
- * We use CAPI's CERT_KEY_IDENTIFIER_PROP_ID property directly.
- */
- case CKA_ID:
- xxxxx
+ ASSERT(0 && "unrecognized type");
break;
-
- /*
- * DER-encoding of the certificate subject name.
- *
- * We use CAPI's CERT_CONTEXT pCertInfo->Subject field
- * directly.
- */
- case CKA_SUBJECT:
- xxxxx
- break;
-
- /*
- * DER-encoding of the certificate issuer name.
- *
- * We use CAPI's CERT_CONTEXT pCertInfo->Issuer field
- * directly.
- */
- case CKA_ISSUER:
- xxxxx
- break;
-
- /*
- * DER-encoding of the certificate serial number.
- *
- * TODO:
- * BOOL rc = CryptEncodeObject(X509_ASN_ENCODING,
- * X509_MULTI_BYTE_INTEGER,
- * &certContext->pCertInfo->SerialNumber,
- * co->derSerial,
- * &size);
- */
- case CKA_SERIAL_NUMBER:
- xxxxx
- break;
-
- /*
- * BER-encoding of the full certificate.
- *
- * We use CAPI's CERT_CONTEXT pbCertEncoded field directly.
- */
- case CKA_VALUE:
- xxxxx
- break;
-
- /*
- * If CKA_VALUE not specified, this is where the full
- * certificate can be found.
- *
- * We don't support this. All our certificates are present
- * in full.
- */
- case CKA_URL:
- break;
-
- /*
- * Checksum
- * - TODO: Work out what to do here
- */
- case CKA_CHECKSUM:
- break;
-
- /*
- * TODO: Should we support these?
- */
- CKA_HASH_OF_SUBJECT_PUBLIC_KEY
- CKA_HASH_OF_ISSUER_PUBLIC_KEY
- break;
-
- /* Not supported */
-
- default:
- break
};
-};
-static xxx
-cert_date_attribute()
-{
- switch(type)
- {
-
- /*
- * Start date for the certificate.
- * - TODO: Work out where to get this.
- */
- pCertInfo->NotBefore;
- case CKA_START_DATE:
- xxxx;
- break;
-
- /*
- * End date for the certificate.
- * - TODO: Work out where to get this.
- */
- pCertInfo->NotAfter;
- case CKA_END_DATE:
- xxxx;
- break;
- };
-}
-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-
-static CK_RV
-cert_ulong_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert,
- CK_ATTRIBUTE_PTR attr)
-{
- CK_ATTRIBUTE_PTR ret;
- CK_BBOOL val;
-
- switch(type)
- {
- case CKA_TOKEN:
- val = CK_TRUE;
- break;
- case CKA_PRIVATE:
- case CKA_MODIFIABLE:
- val = CK_FALSE;
- break;
- };
-
- /* If attr is initialized, just do a match */
- if(attr.type == type)
- {
- if(attr->pValue && attr->ulValueLen == sizeof(CK_BBOOL) &&
- memcmp(attr->pValue, &val, sizeof(CK_BBOOL));
- return CKR_OK;
- return CKR_CANCEL;
- }
-
- /* Otherwise fill in the value */
- else
- {
- return prep_attribute(attr, type, &val, sizeof(CK_BBOOL);
- }
-}
-
-static CK_ATTRIBUTE_PTR
-cert_load_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert)
-{
- CK_BBOOL vval = CK_FALSE;
- CK_ULONG uval = 0;
- CK_VOID_PTR val;
- CK_ULONG n_val;
-
- switch(type)
- {
- case CKA_CLASS:
- uval = CKO_CERTIFICATE;
- break;
- case CKA_TOKEN;
-
- }
-}
-
-static CK_BBOOL
-cert_match_attr(CK_ATTRIBUTE_PTR match, PCCERT_CONTEXT cert)
-{
- CK_ATTRIBUTE_PTR attr;
- CK_BBOOL ret;
-
- attr = cert_load_attribute(match->type, cert);
- if(!attr)
+ /* Value is longer than this one */
+ if(rv == CKR_BUFFER_TOO_SMALL)
+ return CK_FALSE;
+ if(rv != CKR_OK)
return CK_FALSE;
- ret = (attr->ulValueLen == match->ulValueLen &&
- memcmp(attr->pValue, match->pValue, attr->ulValueLen) == 0);
-
- free_attribute(attr);
- return ret;
+ return (match->ulValueLen == len &&
+ memcmp(match->pValue, value, len) == 0);
}
-static CK_BBOOL
-cert_match(CK_ATTRIBUTE_PTR matches, CK_ULONG count,
- PCCERT_CONTEXT cert)
+CK_BBOOL
+ckcapi_object_data_match(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR matches,
+ CK_ULONG count)
{
CK_ULONG i;
for(i = 0; i < count; ++i)
{
- if(!cert_match_attr(&match[i], cert))
+ if(!ckcapi_object_data_match_attr(objdata, &matches[i]))
return CK_FALSE;
}
return CK_TRUE;
}
-static CK_RV
-gather_store_certs(const char* store_name, Array* arr,
- CK_ATTRIBUTE_PTR match, CK_ULONG count)
+CK_RV
+ckcapi_object_data_get_attrs(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG count)
{
- PCCERT_CONTEXT cert = NULL;
- CK_OBJECT_HANDLE obj;
- HCERTSTORE store;
- DWORD err;
- CK_RV ret = CKR_OK;
-
- store = CertOpenSystemStore((HCRYPTPROV)NULL, store_name);
- if(store == NULL)
- {
- err = GetLastError();
-
- /* Store not found, we don't care */
- if(err == ERROR_FILE_NOT_FOUND)
- return CKR_OK;
+ CK_ULONG i;
+ CK_RV rv, ret = CKR_OK;
- else
- return ckcapi_winerr_to_ckr(err);
- }
+ ASSERT(objdata && objdata->data);
+ ASSERT(!count || attrs);
- /* Match each certificate */
- while((cert = CertEnumCertificatesInStore(store, cert)) != NULL)
+ for(i = 0; i < count; ++i)
{
- if(match_cert(match, count, cert))
+ /* Get the data type of the attribute */
+ switch(attribute_data_type(attrs[i].type))
{
- obj = register_cert(store, cert);
- if(!obj)
- {
- ret = CKR_HOST_MEMORY;
- break;
- }
-
- ckcapi_util_array_append(arr, obj);
+ case DATA_BOOL:
+ rv = (objdata->data_funcs.get_bool)(objdata->data, attrs[i].type,
+ attrs[i].pValue, &attrs[i].ulValueLen);
+ break;
+ case DATA_ULONG:
+ rv = (objdata->data_funcs.get_ulong)(objdata->data, attrs[i].type,
+ attrs[i].pValue, &attrs[i].ulValueLen);
+ break;
+ case DATA_BYTES:
+ rv = (objdata->data_funcs.get_bytes)(objdata->data, attrs[i].type,
+ attrs[i].pValue, &attrs[i].ulValueLen);
+ break;
+ case DATA_DATE:
+ rv = (objdata->data_funcs.get_date)(objdata->data, attrs[i].type,
+ attrs[i].pValue, &attrs[i].ulValueLen);
+ break;
+ case DATA_UNKNOWN:
+ rv = CKR_ATTRIBUTE_TYPE_INVALID;
+ break;
+ default:
+ ASSERT(0 && "unrecognized type");
+ break;
+ };
+
+ /* Not an error if they were just requesting the size */
+ if(rv == CKR_BUFFER_TOO_SMALL)
+ {
+ if(!attrs[i].pValue)
+ rv = CKR_OK;
}
- }
- ASSERT(store);
- CertCloseStore(store, 0);
-
- return ret;
-}
-
-/* ----------------------------------------------------------------------------
- * FIND
- */
-
-BOOL
-get_ulong_attribute(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR templ,
- CK_ULONG count, CK_ULONG* val)
-{
- CK_ULONG i;
-
- ASSERT(val);
- ASSERT(!count || templ);
+ /* Is it a fatal error? */
+ else if(rv != CKR_ATTRIBUTE_TYPE_INVALID)
+ {
+ ret = rv;
+ break;
+ }
- for(i = 0; i < count; ++i)
- {
- if(templ[i].type == type)
+ /* Transfer any non-fatal errors outward */
+ if(rv != CKR_OK && ret == CKR_OK)
{
- *val = *((CK_ULONG*)templ[i].pValue);
- return TRUE;
+ ret = rv;
}
}
- return FALSE;
-}
-
-
-
-
-CK_RV
-gather_objects(Array* arr, CK_ATTRIBUTE_PTR match, CK_ULONG count)
-{
- CK_OBJECT_CLASS ocls = CK_INVALID_HANDLE;
- CK_RV ret = CKR_OK;
-
- get_ulong_attribute(CKA_CLASS, match, count, &ocls);
- switch(ocls)
- {
- /* all different classes */
- case CK_INVALID_HANDLE:
- case CKO_CERTIFICATE:
- ret = gather_certificates(arr, match, count);
- break;
- case CKO_PUBLIC_KEY:
- case CKO_PRIVATE_KEY:
- default:
- break;
- };
-
return ret;
-}
-
-void
-cleanup_find_operation(Session* sess)
-{
- ASSERT(sess->operation_type == OPERATION_FIND);
- if(sess->operation_data)
- ckcapi_util_array_free((Array*)sess->operation_data, TRUE);
- sess->operation_type = OPERATION_NONE;
- sess->operation_data = NULL;
- sess->operation_cancel = NULL;
-}
-
-CK_RV
-ckcapi_object_find_init(Session* sess, CK_ATTRIBUTE_PTR match,
- CK_ULONG count)
-{
- Array* arr;
- CK_RV ret;
-
- ASSERT(sess);
- ASSERT(!count || match);
-
- if(sess->operation_type != OPERATION_NONE)
- return CKR_OPERATION_ACTIVE;
-
- arr = ckcapi_util_array_new(0, 1, sizeof(CK_OBJECT_HANDLE));
- if(!arr)
- return CKR_HOST_MEMORY;
-
- ret = gather_objects(arr, match, count);
- if(ret != CKR_OK)
- {
- ckcapi_util_array_free(arr, TRUE);
- return ret;
- }
-
- sess->operation_type = OPERATION_FIND;
- sess->operation_data = arr;
- sess->operation_cancel = cleanup_find_operation;
-
- return CKR_OK;
-}
-
-CK_RV
-ckcapi_object_find(Session* sess, CK_OBJECT_HANDLE_PTR objects,
- CK_ULONG max_object_count, CK_ULONG_PTR object_count)
-{
- Array* arr;
- size_t i;
-
- ASSERT(sess);
- ASSERT(object_count);
- ASSERT(!max_object_count || objects);
-
- if(sess->operation_type != OPERATION_FIND)
- return CKR_OPERATION_NOT_INITIALIZED;
-
- if(!max_object_count)
- {
- *object_count = 0;
- return CKR_OK;
- }
-
- arr = (Array*)sess->operation_data;
- *object_count = (max_object_count > arr->len ? arr->len : max_object_count);
- for(i = 0; i < *object_count; ++i)
- objects[i] = ckcapi_util_array_index(arr, CK_OBJECT_HANDLE, i);
- ckcapi_util_array_remove_range(arr, 0, *object_count);
-
- return CKR_OK;
-}
-
-CK_RV
-ckcapi_objects_find_final(Session* sess)
-{
- ASSERT(sess);
-
- if(sess->operation_type != OPERATION_FIND)
- return CKR_OPERATION_NOT_INITIALIZED;
-
- cleanup_find_operation(sess);
- return CKR_OK;
-}
-
+} \ No newline at end of file