diff options
| author | Stef Walter <stef@memberwebs.com> | 2007-04-27 20:37:40 +0000 | 
|---|---|---|
| committer | Stef Walter <stef@memberwebs.com> | 2007-04-27 20:37:40 +0000 | 
| commit | 4928a4bff079c140d261cb3fefdc07c60c0bdebf (patch) | |
| tree | c5258568f5e417f0a2c9d19099c6ed057cfd73bd | |
| parent | 3d8ed01d2653c45e52821ba00ac72099a12600e1 (diff) | |
A bunch more changes, that implement almost complete find and get support.
| -rw-r--r-- | ckcapi-cert.c | 456 | ||||
| -rw-r--r-- | ckcapi-object.c | 744 | ||||
| -rw-r--r-- | ckcapi-session.c | 168 | ||||
| -rw-r--r-- | ckcapi-util.c | 336 | ||||
| -rw-r--r-- | ckcapi-util.h | 42 | ||||
| -rw-r--r-- | ckcapi.c (renamed from cryptoki-capi.c) | 48 | ||||
| -rw-r--r-- | ckcapi.dsp (renamed from cryptoki-capi.dsp) | 18 | ||||
| -rw-r--r-- | ckcapi.dsw (renamed from cryptoki-capi.dsw) | 0 | ||||
| -rw-r--r-- | ckcapi.h | 160 | ||||
| -rw-r--r-- | cryptoki-capi.h | 99 | 
10 files changed, 1161 insertions, 910 deletions
diff --git a/ckcapi-cert.c b/ckcapi-cert.c index d1b9b32..7436307 100644 --- a/ckcapi-cert.c +++ b/ckcapi-cert.c @@ -1,18 +1,25 @@ +#include "ckcapi.h" -typedef struct _CertRef -{ -	 +#include <memory.h> +#include <wincrypt.h> + +typedef struct _CertObject +{ +	CkCapiObject obj; +	const char* store; +	BYTE* key_id; +	DWORD key_id_len;  } -CertRef; +CertObject;  static CK_RV  copy_static_data(CK_VOID_PTR val, CK_ULONG_PTR len,   				 CK_VOID_PTR data, DWORD cb)  {  	if(cb == 0) -		return CKR_CANCEL; +		return CKR_ATTRIBUTE_TYPE_INVALID;  	if(!val)  	{ @@ -39,7 +46,6 @@ cert_bool_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  	CK_BBOOL val;  	ASSERT(obj); -	ASSERT(ret);  	switch(type)   	{ @@ -79,7 +85,7 @@ cert_bool_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  		/* TODO: Implement */  	default: -		return CK_CANCEL; +		return CKR_ATTRIBUTE_TYPE_INVALID;  	};  	return copy_static_data(data, len, &val, sizeof(CK_BBOOL)); @@ -93,7 +99,6 @@ cert_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  	CK_ULONG val;  	ASSERT(obj); -	ASSERT(ret);  	switch(type)  	{ @@ -102,7 +107,7 @@ cert_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  	 * Object class.  	 * - Always CKO_CERTIFICATE for certificates.  	 */ -	case CKA_OBJECT_CLASS: +	case CKA_CLASS:  		val = CKO_CERTIFICATE;  		break; @@ -123,7 +128,7 @@ cert_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  		/* TODO: Implement */  	default: -		return CK_CANCEL; +		return CKR_ATTRIBUTE_TYPE_INVALID;  	};  	if(*len < sizeof(CK_ULONG)) @@ -137,218 +142,6 @@ cert_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  static CK_RV  cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  -					 CkCapiAttrAction action, CK_ATTRIBUTE_PTR attr) -{ -	PCCERT_CONTEXT cert = (PCCERT_CONTEXT)obj; -	CK_VOID_PTR val; -	CK_ULONG len; -	size_t maxa; -	BOOL r; - - -	DWORD size = *len; - -	int allocated = 0; - -	ASSERT(obj); -	ASSERT(ret); - -	/* -	 * We don't need to retrieve the full value of any of  -	 * these fields if we don't have to. Just calculate  -	 * the max amount to retrieve, so we can compare, or  -	 * notify caller of real length.  -	 */ -	maxa = attr->ulValueLen; -	if(maxa == 0) -		maxa = 4; -	/* Keep dynamic allocations under a 64k. */ -	if(maxa > 0xFFFF) -		maxa = 0xFFFF; -		 -	switch(type) -	{ - -	/* -	 * Description of the object. -	 * - We use CAPI's CERT_FRIENDLY_NAME_PROP_ID property,  -	 *   converted into UTF8. -	 * - Yes this is slow, but this is not really a property -	 *   that's searched on or retrieved intensively. -	 */ -	case CKA_LABEL: -		{ -			DWORD size = maxa * sizeof(WCHAR); -			WCHAR* utf16; -xxxxxx, this is wrong, second call may be needed -			/* Get the UTF16 string, a worst case of twice as long as UTF8 */ -			WCHAR* utf16 = alloca(size); -			r = CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, -												  utf16, &size); -			if(!r) -			{ -				DWORD err = GetLastError(); -				if(err == ERROR_MORE_DATA)  -				{ -					/* Truncate long names */ -					utf16[maxa - 1] = 0;  -					r = TRUE; -				} -				else if (err != CRYPT_E_NOT_FOUND) -				{ -					return ckcapi_winerr_to_ckr(err); -				} -			} - -			if(r) -			{ -				/* Convert it */ -				if(!ckcapi_util_utf16_to_utf8(utf16, &val, &len)) -					SetLastError(ERROR_NOT_ENOUGH_MEMORY); -				allocated = 1; -			} -			else -			{ -				/* We always like to have a decent label */ -				val = "Unnamed Certificate"; -				len = strlen(val); -				allocated = 0; -			} -		} -		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: -		{ -			BOOL r; - -			val = alloca(size); -			r = CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,  -												  val, &size); -			if(!r) -			{ -				DWORD err = GetLastError(); -				if(err == CRYPT_E_NOT_FOUND) -					return CKR_CANCEL; -				if(err != ERROR_MORE_DATA)  -					return ckcapi_winerr_to_ckr(err); -			} - -			*len = size; -		} -		break; - -	/* -	 * DER-encoding of the certificate subject name. -	 *  -	 * We use CAPI's CERT_CONTEXT pCertInfo->Subject field -	 * directly.  -	 */ -	case CKA_SUBJECT: -		if(cert->pCertInfo->Subject.pbData == NULL || -		   cert->pCertInfo->Subject.cbData == 0) -			return CKR_CANCEL; -		val = cert->pCertInfo->Subject.pbData; -		len = cert->pCertInfo->Subject.cbData; -		break; - -	/* -	 * DER-encoding of the certificate issuer name. -	 *  -	 * We use CAPI's CERT_CONTEXT pCertInfo->Issuer field -	 * directly. -	 */ -	case CKA_ISSUER: -		if(cert->pCertInfo->Issuer.pbData == NULL || -		   cert->pCertInfo->Issuer.cbData == 0) -			return CKR_CANCEL; -		val = cert->pCertInfo->Issuer.pbData; -		len = cert->pCertInfo->Issuer.cbData; -		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: -		{ -			BOOL r; -			DWORD size = *len; - -			r = CryptEncodeObject(X509_ASN_ENCODING, X509_MULTI_BYTE_INTEGER, -								  &cert->pCertInfo->SerialNumber, val, *len); -			if(!r) -			{ -				DWORD err = GetLastError(); -				if(err == ERROR_FILE_NOT_FOUND) -					return CKR_GENERAL_ERROR; -				if(err != ERROR_MORE_DATA) -					return ckcapi_winerr_to_ckr(err); -			} - -			len = size; -		} -		break; - -	/* -	 * BER-encoding of the full certificate. -	 * -	 * We use CAPI's CERT_CONTEXT pbCertEncoded field directly. -	 */ -	case CKA_VALUE: -		if(cert->pbCertEncoded == NULL || -		   cert->cbCertEncoded == 0) -			return CKR_CANCEL; -		val = cert->pbCertEncoded; -		len = cert->cbCertEncoded; -		break; -		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: -		return CKR_CANCEL; - -	/* -	 * 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 CK_RV -cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,   					 CK_VOID_PTR data, CK_ULONG_PTR len)  {  	PCCERT_CONTEXT cert = (PCCERT_CONTEXT)obj; @@ -372,8 +165,8 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  			/* Get the UTF16 string, a worst case of twice as long as UTF8 */  			(*len) *= sizeof(WCHAR); -			utf16 = alloca(*len); -			r = CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, +			utf16 = _alloca(*len); +			if(!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,  												  utf16, (DWORD*)len))  			{  				DWORD err = GetLastError(); @@ -384,7 +177,9 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  			}  			/* Convert the data into the buffer */ -			return ckcapi_util_utf16_to_utf8(utf16, data, len)); +			if(!WideCharToMultiByte(CP_UTF8, 0, utf16, -1, data, *len, "?", NULL)) +				return ckcapi_winerr_to_ckr(GetLastError()); +			return CKR_OK;  		}  		break; @@ -402,7 +197,7 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  			{  				DWORD err = GetLastError();  				if(err == CRYPT_E_NOT_FOUND) -					return CKR_CANCEL; +					return CKR_ATTRIBUTE_TYPE_INVALID;  				return ckcapi_winerr_to_ckr(err);  			}  		} @@ -474,27 +269,28 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  	 * Checksum  	 * - TODO: Work out what to do here  	 */ -	case CKA_CHECKSUM: +	case CKA_CHECK_VALUE:  		break;  	/*  	 * TODO: Should we support these?  	 */ -	CKA_HASH_OF_SUBJECT_PUBLIC_KEY -	CKA_HASH_OF_ISSUER_PUBLIC_KEY +	case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: +	case CKA_HASH_OF_ISSUER_PUBLIC_KEY:  		break;  	/* Not supported */  	default: -		break +		break;  	}; -	return CKR_CANCEL; +	return CKR_ATTRIBUTE_TYPE_INVALID;  } -static xxx -cert_date_attribute() +static CK_RV +cert_date_attribute(void* obj, CK_ATTRIBUTE_TYPE type,  +					CK_VOID_PTR data, CK_ULONG_PTR len)  {  	switch(type)  	{ @@ -505,7 +301,6 @@ cert_date_attribute()  	 *	pCertInfo->NotBefore;  	 */  	case CKA_START_DATE: -		xxxx;  		break;  	/* @@ -514,7 +309,198 @@ cert_date_attribute()  	 * pCertInfo->NotBefore;  	 */  	case CKA_END_DATE: -		xxxx;  		break;  	}; + +	return CKR_ATTRIBUTE_TYPE_INVALID; +} + +static void +cert_release(void* data) +{ +	PCCERT_CONTEXT cert = (PCCERT_CONTEXT)data; +	ASSERT(cert); +	CertFreeCertificateContext(cert); +} + +static const CkCapiObjectDataVtable cert_objdata_vtable = { +	cert_bool_attribute, +	cert_ulong_attribute, +	cert_bytes_attribute, +	cert_date_attribute, +	cert_release, +}; + +static CK_RV  +cert_load(CkCapiObject* obj, CkCapiObjectData* objdata) +{ +	CertObject* cobj = (CertObject*)obj; +	HCERTSTORE store; +	PCCERT_CONTEXT cert; +	CRYPT_HASH_BLOB blob; + +	ASSERT(cobj); +	ASSERT(objdata); + +	ASSERT(cobj->store); +	store = CertOpenSystemStore((HCRYPTPROV)NULL, cobj->store); +	if(!store) +		return ckcapi_winerr_to_ckr(GetLastError()); + +	ASSERT(cobj->key_id); +	ASSERT(cobj->key_id_len); +	blob.pbData = cobj->key_id; +	blob.cbData = cobj->key_id_len; + +	cert = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, +									  0, CERT_FIND_KEY_IDENTIFIER, &blob, NULL); + +	CertCloseStore(store, 0); + +	if(!cert) +	{ +		DWORD err = GetLastError(); + +		/* TODO: Is this right for a deleted certificate? */ +		ASSERT(err != E_INVALIDARG); +		if(err == CRYPT_E_NOT_FOUND) +			return CKR_OBJECT_HANDLE_INVALID; +		else +			return ckcapi_winerr_to_ckr(GetLastError()); +	} +	 +	objdata->data = (void*)cert; +	objdata->data_funcs = cert_objdata_vtable; +	return CKR_OK; +} + + +static void  +cert_object_release(void* data) +{ +	CertObject* cobj = (CertObject*)data; +	ASSERT(cobj); +	free(cobj); +} + +static const CkCapiObjectVtable cert_object_vtable = { +	cert_load, +	cert_object_release, +}; + +static CK_RV +register_cert_object(CkCapiSession* sess, const char* store, PCCERT_CONTEXT cert,  +					 CK_OBJECT_HANDLE_PTR id) +{ +	CertObject* cobj; +	CK_RV ret; +	DWORD len; +	 +	if(!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &len)) +	{ +		DBG(("cannot get certificate key identifier: %d", GetLastError())); +		return CKR_ATTRIBUTE_TYPE_INVALID; +	} + +	cobj = calloc(sizeof(CertObject) + len, 1); +	if(!cobj) +		return CKR_HOST_MEMORY; + +	/* Store keyid in allocated area after CertObject */ +	cobj->key_id = (BYTE*)(cobj + 1); +	cobj->key_id_len = len; + +	if(!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID,  +										  cobj->key_id, &(cobj->key_id_len))) +	{ +		DBG(("cannot read certificate key identifier: %d", GetLastError())); +		free(cobj); +		return CKR_ATTRIBUTE_TYPE_INVALID; +	} + +	cobj->store = store; +	cobj->obj.id = 0; +	cobj->obj.unique_key = cobj->key_id; +	cobj->obj.unique_len = cobj->key_id_len; +	cobj->obj.obj_funcs = cert_object_vtable; +	cobj->obj.data_funcs = cert_objdata_vtable; +	 +	ret = ckcapi_object_register(sess, &(cobj->obj)); +	if(ret != CKR_OK) +	{ +		free(cobj); +		return ret; +	} + +	ASSERT(cobj->obj.id != 0); +	*id = cobj->obj.id; +	return CKR_OK; +} + +CK_RV +ckcapi_cert_find_in_store(CkCapiSession* sess, const char* store_name,  +						  CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr) +{ +	PCCERT_CONTEXT cert = NULL; +	CK_OBJECT_HANDLE obj; +	HCERTSTORE store; +	CkCapiObjectData objdata; +	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; + +		else +			return ckcapi_winerr_to_ckr(err); +	} + +	/* Match each certificate */ +	while((cert = CertEnumCertificatesInStore(store, cert)) != NULL) +	{ +		objdata.data = (void*)cert; +		objdata.data_funcs = cert_objdata_vtable; + +		if(ckcapi_object_data_match(&objdata, match, count)) +		{ +			ret = register_cert_object(sess, store, cert, &obj); +			if(ret != CKR_OK) +				break; + +			ckcapi_array_append(arr, obj); +		} +	} + +	ASSERT(store); +	CertCloseStore(store, 0); + +	return ret; +} + +CK_RV +ckcapi_cert_find_all(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,  +					 CK_ULONG count, CkCapiArray* arr) +{ +	CK_RV ret; + +	ret = ckcapi_cert_find_in_store(sess, "My", match, count, arr); +	if(ret == CKR_OK) +		ret = ckcapi_cert_find_in_store(sess, "AddressBook", match, count, arr); +	if(ret == CKR_OK) +		ret = ckcapi_cert_find_in_store(sess, "CA", match, count, arr); +	if(ret == CKR_OK) +		ret = ckcapi_cert_find_in_store(sess, "Root", match, count, arr); +	if(ret == CKR_OK) +		ret = ckcapi_cert_find_in_store(sess, "Trust", match, count, arr); +	if(ret == CKR_OK) +		ret = ckcapi_cert_find_in_store(sess, "TrustedPeople", match, count, arr); +	if(ret == CKR_OK) +		ret = ckcapi_cert_find_in_store(sess, "AuthRoot", match, count, arr); +	return ret;  } 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 diff --git a/ckcapi-session.c b/ckcapi-session.c index dc700c1..1076fbd 100644 --- a/ckcapi-session.c +++ b/ckcapi-session.c @@ -1,10 +1,10 @@  #include <stdlib.h> -#include "cryptoki-capi.h" +#include "ckcapi.h"  typedef struct _SessionList { -	Session **list; +	CkCapiSession **list;  	size_t lmax;  } SessionList; @@ -12,10 +12,10 @@ typedef struct _SessionList {  static SessionList the_sessions = { NULL, 0 }; -Session* +CkCapiSession*  ckcapi_session_create(void)  { -	Session* sess = calloc(1, sizeof(Session)); +	CkCapiSession* sess = calloc(1, sizeof(CkCapiSession));  	if(!sess)  		return NULL; @@ -31,7 +31,7 @@ ckcapi_session_create(void)  }  CK_RV  -ckcapi_session_register(Session* sess) +ckcapi_session_register(CkCapiSession* sess)  {  	CK_ULONG id = 0;  	CK_RV ret = CKR_OK; @@ -67,13 +67,13 @@ ckcapi_session_register(Session* sess)  			/* Couldn't find a handle, reallocate */  			if(id == 0)   			{ -				Session** buf; +				CkCapiSession** buf;  				size_t oldmax, newmax;  				oldmax = the_sessions.lmax;  				newmax = oldmax + 16; -				buf = realloc(the_sessions.list, newmax * sizeof(Session*)); +				buf = realloc(the_sessions.list, newmax * sizeof(CkCapiSession*));  				if(!buf)  				{  					DBGS(sess, ("couldn't allocate session list, out of memory")); @@ -116,7 +116,7 @@ ckcapi_session_register(Session* sess)  }  void -ckcapi_session_destroy(Session* sess) +ckcapi_session_destroy(CkCapiSession* sess)  {  	ASSERT(sess);  	ASSERT(sess->refs == 0); @@ -141,10 +141,10 @@ ckcapi_session_destroy(Session* sess)  }  static CK_RV  -find_lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id,  -					   int remove, Session** sess_ret) +lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id,  +				  int remove, CkCapiSession** sess_ret)  { -	Session *sess; +	CkCapiSession *sess;  	DWORD r;  	ASSERT(sessions); @@ -185,7 +185,7 @@ find_lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id,  		}  	} -	/* Lock the CallSession */ +	/* Lock the CallCkCapiSession */  	r = WaitForSingleObject(sess->mutex, INFINITE);  	ASSERT(r == WAIT_OBJECT_0); @@ -225,7 +225,7 @@ find_lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id,  }  CK_RV -ckcapi_session_find_lock_ref(CK_ULONG id, int remove, Session **sess) +ckcapi_session_get_lock_ref(CK_ULONG id, int remove, CkCapiSession **sess)  {  	/* This must be called without any locks held */ @@ -241,7 +241,7 @@ ckcapi_session_find_lock_ref(CK_ULONG id, int remove, Session **sess)  	ckcapi_lock_global(); -		ret = find_lock_ref_internal (&the_sessions, id, remove, sess); +		ret = lock_ref_internal (&the_sessions, id, remove, sess);  	ckcapi_unlock_global(); @@ -249,9 +249,9 @@ ckcapi_session_find_lock_ref(CK_ULONG id, int remove, Session **sess)  }  void -ckcapi_session_unref_unlock(Session* sess) +ckcapi_session_unref_unlock(CkCapiSession* sess)  { -	/* The CallSession must be locked at this point */ +	/* The CallCkCapiSession must be locked at this point */  	int refs;  	BOOL r; @@ -284,7 +284,7 @@ ckcapi_session_close_all()  	/* This must be called without any locks held */  	SessionList sessions; -	Session *sess; +	CkCapiSession *sess;  	size_t i;  	CK_RV ret; @@ -313,7 +313,7 @@ ckcapi_session_close_all()  		if(!sessions.list[i])  			continue; -		ret = find_lock_ref_internal (&sessions, i, 1, &sess); +		ret = lock_ref_internal (&sessions, i, 1, &sess);  		ASSERT(ret == CKR_OK);  		ckcapi_session_unref_unlock(sess); @@ -327,3 +327,135 @@ ckcapi_session_close_all()  	}  } +/* ---------------------------------------------------------------------------- + * FIND OPERATION + */ + +static 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); + +	for(i = 0; i < count; ++i) +	{ +		if(templ[i].type == type) +		{ +			*val = *((CK_ULONG*)templ[i].pValue); +			return TRUE; +		} +	} + +	return FALSE; +} + +static CK_RV +gather_objects(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,  +			   CK_ULONG count, CkCapiArray* arr) +{ +	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 = ckcapi_cert_find_all(sess, match, count, arr);  +		break; +	case CKO_PUBLIC_KEY: +	case CKO_PRIVATE_KEY: +	default: +		break; +	}; + +	return ret; +} + +void  +cleanup_find_operation(CkCapiSession* sess) +{ +	ASSERT(sess->operation_type == OPERATION_FIND); +	if(sess->operation_data) +		ckcapi_array_free((CkCapiArray*)sess->operation_data, TRUE); +	sess->operation_type = OPERATION_NONE; +	sess->operation_data = NULL; +	sess->operation_cancel = NULL; +} + +CK_RV +ckcapi_session_find_init(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,  +						 CK_ULONG count) +{ +	CkCapiArray* arr; +	CK_RV ret; + +	ASSERT(sess); +	ASSERT(!count || match); + +	if(sess->operation_type != OPERATION_NONE) +		return CKR_OPERATION_ACTIVE; + +	arr = ckcapi_array_new(0, 1, sizeof(CK_OBJECT_HANDLE)); +	if(!arr) +		return CKR_HOST_MEMORY; + +	ret = gather_objects(sess, match, count, arr); +	if(ret != CKR_OK)  +	{ +		ckcapi_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_session_find(CkCapiSession* sess, CK_OBJECT_HANDLE_PTR objects,  +			 	    CK_ULONG max_object_count, CK_ULONG_PTR object_count) +{ +	CkCapiArray* 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 = (CkCapiArray*)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_array_index(arr, CK_OBJECT_HANDLE, i); +	ckcapi_array_remove_range(arr, 0, *object_count); + +	return CKR_OK; +} + +CK_RV +ckcapi_session_find_final(CkCapiSession* sess) +{ +	ASSERT(sess); + +	if(sess->operation_type != OPERATION_FIND) +		return CKR_OPERATION_NOT_INITIALIZED; + +	cleanup_find_operation(sess); +	return CKR_OK; +} + diff --git a/ckcapi-util.c b/ckcapi-util.c index d8d182b..6969c2e 100644 --- a/ckcapi-util.c +++ b/ckcapi-util.c @@ -1,17 +1,16 @@ -#include "cryptoki-capi-util.h" +#include "ckcapi-util.h" +#include <sys/types.h> +#include <stdlib.h>  #include <string.h> - - -  #define MIN_ARRAY_SIZE  16  typedef struct _RealArray  { -	Array pub; +	CkCapiArray pub;  	size_t alloc;  	size_t elt_size;  	int zero_terminated : 1; @@ -44,7 +43,7 @@ maybe_expand(RealArray *array, size_t len)  									  array->zero_terminated);  	if(want_alloc > array->alloc) -    { +	{  		want_alloc = nearest_pow(want_alloc);  		want_alloc = want_alloc > MIN_ARRAY_SIZE ? want_alloc : MIN_ARRAY_SIZE; @@ -53,21 +52,21 @@ maybe_expand(RealArray *array, size_t len)  			return 0;  		array->pub.data = mem; -        memset((char*)array->pub.data + array->alloc, 0, want_alloc - array->alloc); +		memset((char*)array->pub.data + array->alloc, 0, want_alloc - array->alloc);  		array->alloc = want_alloc;  	}  	return 1;  } -Array* -ckcapi_util_array_new(int zero_terminated, int clear, size_t elt_size) +CkCapiArray* +ckcapi_array_new(int zero_terminated, int clear, size_t elt_size)  { -	return ckcapi_util_array_sized_new(zero_terminated, clear, elt_size, 0); +	return ckcapi_array_sized_new(zero_terminated, clear, elt_size, 0);  } -Array*  -ckcapi_util_array_sized_new(int zero_terminated, int clear, size_t elt_size, +CkCapiArray*  +ckcapi_array_sized_new(int zero_terminated, int clear, size_t elt_size,  							size_t reserved_size)  {  	RealArray *array = malloc(sizeof(RealArray)); @@ -87,11 +86,11 @@ ckcapi_util_array_sized_new(int zero_terminated, int clear, size_t elt_size,  		array_zero_terminate(array);  	} -	return (Array*)array; +	return (CkCapiArray*)array;  }  void* -ckcapi_util_array_free(Array* array, int free_segment) +ckcapi_array_free(CkCapiArray* array, int free_segment)  {  	void* segment; @@ -99,10 +98,10 @@ ckcapi_util_array_free(Array* array, int free_segment)  		return NULL;  	if(free_segment) -    { +	{  		free(array->data);  		segment = NULL; -    } +	}  	else  		segment = array->data; @@ -111,7 +110,7 @@ ckcapi_util_array_free(Array* array, int free_segment)  }  int -ckcapi_util_array_append_vals(Array* parray, const void* data, size_t len) +ckcapi_array_append_vals(CkCapiArray* parray, const void* data, size_t len)  {  	RealArray* array = (RealArray*)parray;  	if(!maybe_expand(array, len)) @@ -127,7 +126,7 @@ ckcapi_util_array_append_vals(Array* parray, const void* data, size_t len)  }  void -ckcapi_util_array_remove_index(Array* parray, unsigned int index) +ckcapi_array_remove_index(CkCapiArray* parray, unsigned int index)  {  	RealArray* array = (RealArray*)parray; @@ -136,16 +135,16 @@ ckcapi_util_array_remove_index(Array* parray, unsigned int index)  	if(index != array->pub.len - 1)  		memmove(array_elt_pos (array, index), -			    array_elt_pos (array, index + 1), -				array_elt_len (array, array->pub.len - index - 1)); +		        array_elt_pos (array, index + 1), +		        array_elt_len (array, array->pub.len - index - 1));  	array->pub.len -= 1; -    array_elt_zero (array, array->pub.len, 1); +	array_elt_zero (array, array->pub.len, 1);  }  void -ckcapi_util_array_remove_range(Array* parray, unsigned int index, size_t length) +ckcapi_array_remove_range(CkCapiArray* parray, unsigned int index, size_t length)  {  	RealArray *array = (RealArray*)parray; @@ -162,6 +161,297 @@ ckcapi_util_array_remove_range(Array* parray, unsigned int index, size_t length)  				(array->pub.len - (index + length)) * array->elt_size);  	array->pub.len -= length; -    array_elt_zero(array, array->pub.len, length); +	array_elt_zero(array, array->pub.len, length); +} + + +/* + * Originally from apache 2.0 + * Modifications for general use by <nielsen@memberwebs.com> + */ + +/* Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *         http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#define KEY_DATA(he)	((he)->key) + +/* + * The internal form of a hash table. + * + * The table is an array indexed by the hash of the key; collisions + * are resolved by hanging a linked list of hash entries off each + * element of the array. Although this is a really simple design it + * isn't too bad given that pools have a low allocation overhead. + */ + +typedef struct _HashEntry  +{ +	struct _HashEntry* next; +	unsigned int hash; +	const void* key; +	size_t klen; +	const void* val;  } +HashEntry; + +/* + * The size of the array is always a power of two. We use the maximum + * index rather than the size so that we can use bitwise-AND for + * modular arithmetic. + * The count of hash entries may be greater depending on the chosen + * collision rate. + */ +struct _CkCapiHash  +{ +	HashEntry** array; +	size_t count; +	size_t max; +}; + +#define INITIAL_MAX 15 /* tunable == 2^n - 1 */ + +/* + * Hash creation functions. + */ + +static HashEntry**  +alloc_array(CkCapiHash* ht, size_t max) +{ +	return calloc(sizeof(*(ht->array)) * (max + 1), 1); +} + +CkCapiHash*  +ckcapi_hash_new() +{ +	CkCapiHash* ht = malloc(sizeof(CkCapiHash)); +	if(ht) +	{ +		ht->count = 0; +		ht->max = INITIAL_MAX; +		ht->array = alloc_array(ht, ht->max); +		if(!ht->array) +		{ +			free(ht); +			ht = NULL; +		} +	} +	return ht; +} + +void  +ckcapi_hash_free(CkCapiHash* ht) +{ +	HashEntry* he; +	HashEntry* next; +	size_t i; + +	for(i = 0; i < ht->max; ++i) +	{ +		for(he = ht->array[i]; he; ) +		{ +			next = he->next; +			free(he); +			he = next; +		} +	} +		 +	if(ht->array) +		free(ht->array);	 +	free(ht); +} + +/* + * Expanding a hash table + */ +static int  +expand_array(CkCapiHash* ht) +{ +	HashEntry** new_array; +	size_t new_max; +	HashEntry* he; +	size_t i; + +	new_max = ht->max * 2 + 1; +	new_array = alloc_array(ht, new_max); +	 +	if(!new_array) +		return 0; +		 +	for(i = 0; i < ht->max; ++i) +	{ +		for(he = ht->array[i]; he; he = he->next) +		{ +			unsigned int i = he->hash & new_max; +			he->next = new_array[i]; +			new_array[i] = he; +		} +	} + +	if(ht->array) +		free(ht->array); +	 +	ht->array = new_array; +	ht->max = new_max; +	return 1; +} + +/* + * This is where we keep the details of the hash function and control + * the maximum collision rate. + * + * If val is non-NULL it creates and initializes a new hash entry if + * there isn't already one there; it returns an updatable pointer so + * that hash entries can be removed. + */ + +static HashEntry**  +find_entry(CkCapiHash* ht, const void* key, size_t klen, const void* val) +{ +	HashEntry** hep; +	HashEntry* he; +	const unsigned char* p; +	unsigned int hash; +	size_t i; + +	/* +	 * This is the popular `times 33' hash algorithm which is used by +	 * perl and also appears in Berkeley DB. This is one of the best +	 * known hash functions for strings because it is both computed +	 * very fast and distributes very well. +	 * +	 * The originator may be Dan Bernstein but the code in Berkeley DB +	 * cites Chris Torek as the source. The best citation I have found +	 * is "Chris Torek, Hash function for text in C, Usenet message +	 * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich +	 * Salz's USENIX 1992 paper about INN which can be found at +	 * <http://citeseer.nj.nec.com/salz92internetnews.html>. +	 * +	 * The magic of number 33, i.e. why it works better than many other +	 * constants, prime or not, has never been adequately explained by +	 * anyone. So I try an explanation: if one experimentally tests all +	 * multipliers between 1 and 256 (as I did while writing a low-level +	 * data structure library some time ago) one detects that even +	 * numbers are not useable at all. The remaining 128 odd numbers +	 * (except for the number 1) work more or less all equally well. +	 * They all distribute in an acceptable way and this way fill a hash +	 * table with an average percent of approx. 86%. +	 * +	 * If one compares the chi^2 values of the variants (see +	 * Bob Jenkins ``Hashing Frequently Asked Questions'' at +	 * http://burtleburtle.net/bob/hash/hashfaq.html for a description +	 * of chi^2), the number 33 not even has the best value. But the +	 * number 33 and a few other equally good numbers like 17, 31, 63, +	 * 127 and 129 have nevertheless a great advantage to the remaining +	 * numbers in the large set of possible multipliers: their multiply +	 * operation can be replaced by a faster operation based on just one +	 * shift plus either a single addition or subtraction operation. And +	 * because a hash function has to both distribute good _and_ has to +	 * be very fast to compute, those few numbers should be preferred. +	 * +	 *                        -- Ralf S. Engelschall <rse@engelschall.com> +	 */ + +	hash = 0; +	for(p = key, i = klen; i; i--, p++)  +		hash = hash * 33 + *p; + +	/* scan linked list */ +	for(hep = &ht->array[hash & ht->max], he = *hep; +		he; hep = &he->next, he = *hep)  +	{ +		if(he->hash == hash && he->klen == klen &&  +		   memcmp(KEY_DATA(he), key, klen) == 0) +			break; +	} +	 +	if(he || !val) +		return hep; + +	/* add a new entry for non-NULL val */ +	he = malloc(sizeof(*he)); +	if(he) +	{ +		/* Key points to external data */ +		he->key = key; +		he->klen = klen; + +		he->next = NULL; +		he->hash = hash; +		he->val	= val; +	  +		*hep = he;		 +		ht->count++; +	} +	 +	return hep; +} + +void*  +ckcapi_hash_get(CkCapiHash* ht, const void *key, size_t klen) +{ +	HashEntry** he = find_entry(ht, key, klen, NULL); +	if(he && *he) +		return (void*)((*he)->val); +	else +		return NULL; +} + +int  +ckcapi_hash_set(CkCapiHash* ht, const void* key, size_t klen, void* val) +{ +	HashEntry** hep = find_entry(ht, key, klen, val);	 +	if(hep && *hep)  +	{ +		/* replace entry */ +		(*hep)->val = val; +			 +		/* check that the collision rate isn't too high */ +		if(ht->count > ht->max)  +		{ +			if(!expand_array(ht)) +				return 0; +		} + +		return 1; +	} +	 +	return 0; +} + +void*  +ckcapi_hash_rem(CkCapiHash* ht, const void* key, size_t klen) +{ +	HashEntry** hep = find_entry(ht, key, klen, NULL); +	void* val = NULL; + +	if(hep && *hep) +	{ +		HashEntry* old = *hep; +		*hep = (*hep)->next; +		--ht->count; +		val = (void*)old->val; +		free(old); +	} +	 +	return val; +} +		 +size_t  +ckcapi_hash_count(CkCapiHash* ht) +{ +	return ht->count; +} diff --git a/ckcapi-util.h b/ckcapi-util.h index b37ea39..ea3d5e2 100644 --- a/ckcapi-util.h +++ b/ckcapi-util.h @@ -5,13 +5,6 @@  #include <stdlib.h>  /* -------------------------------------------------------------------------------- - * WINDOWS - */ - -CK_RV		ckcapi_util_win_to_cryptoki_err			(DWORD werr); - - -/* --------------------------------------------------------------------------------   * ARRAYS   */ @@ -20,27 +13,42 @@ typedef struct _Array  	void* data;  	size_t len;  }  -Array; +CkCapiArray; -#define ckcapi_util_array_append(a,v) \ -	ckcapi_util_array_append_vals(a, &(v), 1) -#define ckcapi_util_array_index(a,t,i) \ +#define ckcapi_array_append(a,v) \ +	ckcapi_array_append_vals(a, &(v), 1) +#define ckcapi_array_index(a,t,i) \  	(((t*) (a)->data) [(i)]) -Array*		ckcapi_util_array_new			(int zero_terminated, int zero,  +CkCapiArray*		ckcapi_array_new			(int zero_terminated, int zero,   											 size_t element_size); -Array*		ckcapi_util_array_sized_new		(int zero_terminated, int zero,  +CkCapiArray*		ckcapi_array_sized_new		(int zero_terminated, int zero,   											 size_t element_size, size_t reserved_size); -void*		ckcapi_util_array_free			(Array* array, int free_segment); +void*		ckcapi_array_free			(CkCapiArray* array, int free_segment); -int			ckcapi_util_array_append_vals	(Array* array, const void* data, +int			ckcapi_array_append_vals	(CkCapiArray* array, const void* data,  											 size_t num); -void		ckcapi_util_array_remove_index	(Array* array, unsigned int index); +void		ckcapi_array_remove_index	(CkCapiArray* array, unsigned int index); -void		ckcapi_util_array_remove_range   (Array* array, unsigned int index,  +void		ckcapi_array_remove_range   (CkCapiArray* array, unsigned int index,   											  size_t count); + +/* -------------------------------------------------------------------------------- + * HASHTABLE + */ + +struct _CkCapiHash; +typedef struct _CkCapiHash CkCapiHash; + +CkCapiHash* ckcapi_hash_new(); +void ckcapi_hash_free(CkCapiHash* ht); +size_t ckcapi_hash_count(CkCapiHash* ht); +void* ckcapi_hash_get(CkCapiHash* ht, const void* key, size_t klen); +int ckcapi_hash_set(CkCapiHash* ht, const void* key, size_t klen, void* val); +void* ckcapi_hash_rem(CkCapiHash* ht, const void* key, size_t klen); +  #endif /* __CKCAPI_UTIL_H__ */
\ No newline at end of file diff --git a/cryptoki-capi.c b/ckcapi.c index b100e25..971b034 100644 --- a/cryptoki-capi.c +++ b/ckcapi.c @@ -3,7 +3,7 @@  #include <stdarg.h>  #include <stdio.h> -#include "cryptoki-capi.h" +#include "ckcapi.h"  /* -------------------------------------------------------------------   * GLOBALS / DEFINES  @@ -371,7 +371,7 @@ static CK_RV  CC_C_OpenSession(CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR application,                   CK_NOTIFY notify, CK_SESSION_HANDLE_PTR session)  { -	Session* sess; +	CkCapiSession* sess;  	CK_RV ret;  	ENTER(C_OpenSession); @@ -405,14 +405,14 @@ CC_C_OpenSession(CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR application,  static CK_RV  CC_C_CloseSession(CK_SESSION_HANDLE session)  { -	Session* sess; +	CkCapiSession* sess;  	CK_RV ret;  	ENTER(C_CloseSession);  	PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);  	/* The 'remove' flag removes it from the main session list */ -	ret = ckcapi_session_find_lock_ref(session, 1, &sess); +	ret = ckcapi_session_get_lock_ref(session, 1, &sess);  	if(ret == CKR_OK)  	{  		/* This will unref and possibly destroy the session */ @@ -576,11 +576,29 @@ static CK_RV  CC_C_GetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,                         CK_ATTRIBUTE_PTR templ, CK_ULONG count)  { +	CkCapiSession* sess; +	CkCapiObjectData objdata; +	CK_RV ret; +  	ENTER(C_GetAttributeValue);  	PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); +	PREREQ(object, CKR_OBJECT_HANDLE_INVALID); +	PREREQ(!count || templ, CKR_ARGUMENTS_BAD); +	 +	ret = ckcapi_session_get_lock_ref(session, 0, &sess); +	if(ret == CKR_OK) +	{ +		ret = ckcapi_object_load_data_for(sess, object, &objdata); +		if(ret == CKR_OK) +		{ +			ret = ckcapi_object_data_get_attrs(&objdata, templ, count); +			ckcapi_object_data_release(&objdata); +		} -	/* TODO: Implement this */ -	RETURN(CKR_FUNCTION_NOT_SUPPORTED); +		ckcapi_session_unref_unlock(sess); +	} + +	RETURN(ret);  }  static CK_RV @@ -598,17 +616,17 @@ static CK_RV  CC_C_FindObjectsInit(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR templ,                       CK_ULONG count)  { -	Session* sess; +	CkCapiSession* sess;  	CK_RV ret;  	ENTER(C_FindObjectsInit);  	PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);  	PREREQ(!count || templ, CKR_ARGUMENTS_BAD); -	ret = ckcapi_session_find_lock_ref(session, 0, &sess); +	ret = ckcapi_session_get_lock_ref(session, 0, &sess);  	if(ret == CKR_OK)  	{ -		ret = ckcapi_object_find_init(sess, templ, count); +		ret = ckcapi_session_find_init(sess, templ, count);  		ckcapi_session_unref_unlock(sess);  	} @@ -619,7 +637,7 @@ static CK_RV  CC_C_FindObjects(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects,                   CK_ULONG max_object_count, CK_ULONG_PTR object_count)  { -	Session* sess; +	CkCapiSession* sess;  	CK_RV ret;  	ENTER(C_FindObjects); @@ -627,10 +645,10 @@ CC_C_FindObjects(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects,  	PREREQ(object_count, CKR_ARGUMENTS_BAD);  	PREREQ(!max_object_count || objects, CKR_ARGUMENTS_BAD); -	ret = ckcapi_session_find_lock_ref(session, 0, &sess); +	ret = ckcapi_session_get_lock_ref(session, 0, &sess);  	if(ret == CKR_OK)  	{ -		ret = ckcapi_object_find(sess, objects, max_object_count, object_count); +		ret = ckcapi_session_find(sess, objects, max_object_count, object_count);  		ckcapi_session_unref_unlock(sess);  	} @@ -640,16 +658,16 @@ CC_C_FindObjects(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects,  static CK_RV  CC_C_FindObjectsFinal(CK_SESSION_HANDLE session)  { -	Session* sess; +	CkCapiSession* sess;  	CK_RV ret;  	ENTER(C_FindObjectsFinal);  	PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); -	ret = ckcapi_session_find_lock_ref(session, 0, &sess); +	ret = ckcapi_session_get_lock_ref(session, 0, &sess);  	if(ret == CKR_OK)  	{ -		ret = ckcapi_objects_find_final(sess); +		ret = ckcapi_session_find_final(sess);  		ckcapi_session_unref_unlock(sess);  	} diff --git a/cryptoki-capi.dsp b/ckcapi.dsp index 6f93ed3..a5b73e8 100644 --- a/cryptoki-capi.dsp +++ b/ckcapi.dsp @@ -8,12 +8,12 @@ CFG=cryptoki_capi - Win32 Debug  !MESSAGE This is not a valid makefile. To build this project using NMAKE,  !MESSAGE use the Export Makefile command and run  !MESSAGE  -!MESSAGE NMAKE /f "cryptoki-capi.mak". +!MESSAGE NMAKE /f "ckcapi.mak".  !MESSAGE   !MESSAGE You can specify a configuration when running NMAKE  !MESSAGE by defining the macro CFG on the command line. For example:  !MESSAGE  -!MESSAGE NMAKE /f "cryptoki-capi.mak" CFG="cryptoki_capi - Win32 Debug" +!MESSAGE NMAKE /f "ckcapi.mak" CFG="cryptoki_capi - Win32 Debug"  !MESSAGE   !MESSAGE Possible choices for configuration are:  !MESSAGE  @@ -90,19 +90,23 @@ LINK32=link.exe  # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"  # Begin Source File +SOURCE=".\ckcapi-cert.c" +# End Source File +# Begin Source File +  SOURCE=".\ckcapi-object.c"  # End Source File  # Begin Source File -SOURCE=".\ckcapi-util.c" +SOURCE=".\ckcapi-session.c"  # End Source File  # Begin Source File -SOURCE=".\cryptoki-capi-session.c" +SOURCE=".\ckcapi-util.c"  # End Source File  # Begin Source File -SOURCE=".\cryptoki-capi.c" +SOURCE=.\ckcapi.c  # End Source File  # End Group  # Begin Group "Header Files" @@ -110,11 +114,11 @@ SOURCE=".\cryptoki-capi.c"  # PROP Default_Filter "h;hpp;hxx;hm;inl"  # Begin Source File -SOURCE=".\cryptoki-capi-util.h" +SOURCE=".\ckcapi-util.h"  # End Source File  # Begin Source File -SOURCE=".\cryptoki-capi.h" +SOURCE=.\ckcapi.h  # End Source File  # Begin Source File diff --git a/cryptoki-capi.dsw b/ckcapi.dsw index 7f71040..7f71040 100644 --- a/cryptoki-capi.dsw +++ b/ckcapi.dsw diff --git a/ckcapi.h b/ckcapi.h new file mode 100644 index 0000000..6442a8d --- /dev/null +++ b/ckcapi.h @@ -0,0 +1,160 @@ +#ifndef CKCAPI_H +#define CKCAPI_H + +#ifndef ASSERT +#include "assert.h" +#define ASSERT assert +#endif + +#define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x400 +#include <windows.h> + +#define CRYPTOKI_EXPORTS +#include "pkcs11/cryptoki.h" + +#include "ckcapi-util.h" + +struct _CkCapiObject; +struct _CkCapiSession; + +/* ------------------------------------------------------------------ + * cryptoki-capi.c + */ + +#define DBG(args) \ +	ckcapi_debug args + +void ckcapi_debug(const char* msg, ...); +void ckcapi_lock_global(void); +void ckcapi_unlock_global(void); +CK_RV	ckcapi_winerr_to_ckr		(DWORD werr); + +/* ------------------------------------------------------------------  + * cryptoki-capi-session.c + */ + +/* For operation_type in CkCapiSession */ +enum +{ +	OPERATION_NONE = 0, +	OPERATION_FIND = 1, +}; + +typedef void (*CkCapiSessionCancel) (struct _CkCapiSession* sess); + +typedef struct _CkCapiSession  +{ +	CK_ULONG id;                    /* Unique ID for this session */ +	int in_call;					/* Whether this session is use in PKCS#11 function */ + +	int operation_type;				/* Whether an operation is happening or not */ +	void* operation_data;			/* Data for this operation */ +	CkCapiSessionCancel operation_cancel;	/* Callback to cancel operation when necessary */ + +	CK_NOTIFY notify_callback;      /* Application specified callback */ +	CK_VOID_PTR user_data;          /* Argument for above */ + +	int refs;                       /* Reference count */ +	HANDLE mutex;					/* Mutex for protecting this structure */ +}  +CkCapiSession; + +#define DBGS(sess, msg) \ +	ckcapi_debug("S%d: %s", (sess) ? (sess)->id : 0, (msg)) + +CkCapiSession* ckcapi_session_create(void); +void ckcapi_session_destroy(CkCapiSession* sess); +CK_RV ckcapi_session_register(CkCapiSession* sess); +CK_RV ckcapi_session_get_lock_ref(CK_ULONG id, int remove, CkCapiSession **sess); +void ckcapi_session_unref_unlock(CkCapiSession* sess); +void ckcapi_session_close_all(); + +CK_RV		ckcapi_session_find_init			(CkCapiSession* sess, CK_ATTRIBUTE_PTR templ, CK_ULONG count); +CK_RV		ckcapi_session_find				(CkCapiSession* sess, CK_OBJECT_HANDLE_PTR objects,  +											 CK_ULONG max_object_count, CK_ULONG_PTR object_count); +CK_RV		ckcapi_session_find_final		(CkCapiSession* sess); + + + +/* ------------------------------------------------------------------  + * ckcapi-object.c + */ + +typedef CK_RV (*CkCapiGetAttribute)(void* obj, CK_ATTRIBUTE_TYPE type,  +								    CK_VOID_PTR data, CK_ULONG_PTR len); + +typedef void (*CkCapiRelease)(void* value); + +typedef struct _CkCapiObjectDataVtable +{ +	CkCapiGetAttribute get_bool; +	CkCapiGetAttribute get_ulong; +	CkCapiGetAttribute get_bytes; +	CkCapiGetAttribute get_date; +	CkCapiRelease release; +} +CkCapiObjectDataVtable; + +typedef struct _CkCapiObjectData +{ +	void* data; +	CkCapiObjectDataVtable data_funcs; +} +CkCapiObjectData; + +typedef CK_RV (*CkCapiLoadData)(struct _CkCapiObject* obj, CkCapiObjectData* objdata); + +typedef struct _CkCapiObjectVtable +{ +	CkCapiLoadData load_data; +	CkCapiRelease release; +} +CkCapiObjectVtable; + +typedef struct _CkCapiObject +{ +	CK_OBJECT_HANDLE id; +	void* unique_key; +	size_t unique_len; +	CkCapiObjectVtable obj_funcs; +	CkCapiObjectDataVtable data_funcs; +} +CkCapiObject; + +#define DBGO(obj, msg) \ +	ckcapi_debug("O%d: %s", (obj) ? (obj)->id : 0, (msg)) + +CkCapiObject*		ckcapi_object_lookup			(CkCapiSession* sess, CK_OBJECT_HANDLE obj); + +CK_RV				ckcapi_object_register			(CkCapiSession* sess, CkCapiObject* obj); + +CK_RV				ckcapi_object_load_data			(CkCapiObject* obj, CkCapiObjectData* objdata); + +CK_RV				ckcapi_object_load_data_for		(CkCapiSession* sess, CK_OBJECT_HANDLE hand,  +													 CkCapiObjectData* objdata); + +CK_BBOOL			ckcapi_object_data_match		(CkCapiObjectData* objdata,  +													 CK_ATTRIBUTE_PTR matches, CK_ULONG count); + +CK_BBOOL			ckcapi_object_data_match_attr	(CkCapiObjectData* objdata,  +													 CK_ATTRIBUTE_PTR match); + +CK_RV				ckcapi_object_data_get_attrs	(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attrs,  +													 CK_ULONG count); + +void				ckcapi_object_data_release		(CkCapiObjectData* objdata); + +/* ------------------------------------------------------------------- + * ckcapi-cert.c + */ + +CK_RV				ckcapi_cert_find_all			(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,  +													 CK_ULONG count, CkCapiArray* arr); + +CK_RV				ckcapi_cert_find_in_store		(CkCapiSession* sess, const char* store_name,  +													 CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr); + + +#endif /* CRYPTOKI_CAPI_H */ + diff --git a/cryptoki-capi.h b/cryptoki-capi.h deleted file mode 100644 index a5dc9d5..0000000 --- a/cryptoki-capi.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef CRYPTOKI_CAPI_H -#define CRYPTOKI_CAPI_H - -#ifndef ASSERT -#include "assert.h" -#define ASSERT assert -#endif - -#define WIN32_LEAN_AND_MEAN -#define _WIN32_WINNT 0x400 -#include <windows.h> - -#define CRYPTOKI_EXPORTS -#include "pkcs11/cryptoki.h" - -#include "cryptoki-capi-util.h" - -struct _Object; -struct _Session; - -/* ------------------------------------------------------------------ - * cryptoki-capi.c - */ - -#define DBG(args) \ -	ckcapi_debug args - -void ckcapi_debug(const char* msg, ...); -void ckcapi_lock_global(void); -void ckcapi_unlock_global(void); -CK_RV	ckcapi_winerr_to_ckr		(DWORD werr); - -/* ------------------------------------------------------------------  - * cryptoki-capi-session.c - */ - -/* For operation_type in Session */ -enum -{ -	OPERATION_NONE = 0, -	OPERATION_FIND = 1, -}; - -typedef void (*SessionCancel) (struct _Session* sess); - -typedef struct _Session  -{ -	CK_ULONG id;                    /* Unique ID for this session */ -	int in_call;					/* Whether this session is use in PKCS#11 function */ - -	int operation_type;				/* Whether an operation is happening or not */ -	void* operation_data;			/* Data for this operation */ -	SessionCancel operation_cancel;	/* Callback to cancel operation when necessary */ - -	CK_NOTIFY notify_callback;      /* Application specified callback */ -	CK_VOID_PTR user_data;          /* Argument for above */ - -	int refs;                       /* Reference count */ -	HANDLE mutex;					/* Mutex for protecting this structure */ -}  -Session; - -#define DBGS(sess, msg) \ -	ckcapi_debug("S%d: %s", (sess) ? (sess)->id : 0, (msg)) - -Session* ckcapi_session_create(void); -void ckcapi_session_destroy(Session* sess); -CK_RV ckcapi_session_register(Session* sess); -CK_RV ckcapi_session_find_lock_ref(CK_ULONG id, int remove, Session **sess); -void ckcapi_session_unref_unlock(Session* sess); -void ckcapi_session_close_all(); - - -/* ------------------------------------------------------------------  - * cryptoki-capi-object.c - */ - -typedef struct _Object -{ -	CK_ULONG id;					/* Unique ID for this object */ - -	CK_ATTRIBUTE_PTR attrs;			/* All the attributes of this object */ -	CK_ULONG n_attrs;				/* Number of attributes */ -} -Object; - -/* -Object* ckcapi_object_create(Session* sess, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs); -void ckcapi_object_destroy(Session* sess, Object* obj); -*/ - -CK_RV		ckcapi_object_find_init			(Session* sess, CK_ATTRIBUTE_PTR templ, CK_ULONG count); -CK_RV		ckcapi_object_find				(Session* sess, CK_OBJECT_HANDLE_PTR objects,  -											 CK_ULONG max_object_count, CK_ULONG_PTR object_count); -CK_RV		ckcapi_objects_find_final		(Session* sess); - - -#endif /* CRYPTOKI_CAPI_H */ -  | 
