summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2007-05-06 02:02:09 +0000
committerStef Walter <stef@memberwebs.com>2007-05-06 02:02:09 +0000
commit16be360038c56328695f1dd8133718f82cd0c36c (patch)
tree9428cd853b4561b4590d4102ee81bd57261826b9
parent856a057fc0a0807e9c0dd2b11c04e1f1312bdb12 (diff)
A bunch of trust work on the plugin.
-rw-r--r--ckcapi-builtin.c14
-rw-r--r--ckcapi-cert.c222
-rw-r--r--ckcapi-object.c21
-rw-r--r--ckcapi-session.c64
-rw-r--r--ckcapi-trust.c437
-rw-r--r--ckcapi.c28
-rw-r--r--ckcapi.dsp4
-rw-r--r--ckcapi.dsw14
-rw-r--r--ckcapi.h48
-rw-r--r--x509-usages.h39
10 files changed, 776 insertions, 115 deletions
diff --git a/ckcapi-builtin.c b/ckcapi-builtin.c
index 94d170e..ad70ea2 100644
--- a/ckcapi-builtin.c
+++ b/ckcapi-builtin.c
@@ -91,7 +91,7 @@ static const CkCapiObjectDataVtable builtin_objdata_vtable = {
};
static CK_RV
-builtin_load(CkCapiObject* obj, CkCapiObjectData* objdata)
+builtin_load_data(CkCapiSession* sess, CkCapiObject* obj, CkCapiObjectData* objdata)
{
BuiltinObject* bobj = (BuiltinObject*)obj;
@@ -118,12 +118,12 @@ builtin_object_release(void* data)
}
static const CkCapiObjectVtable builtin_object_vtable = {
- builtin_load,
+ builtin_load_data,
builtin_object_release,
};
static CK_RV
-register_builtin_object(CkCapiSession* sess, CK_ULONG index, CK_OBJECT_HANDLE_PTR id)
+register_builtin_object(CkCapiSession* sess, CK_ULONG index, CkCapiObject** obj)
{
BuiltinObject* bobj;
CK_RV ret;
@@ -148,15 +148,15 @@ register_builtin_object(CkCapiSession* sess, CK_ULONG index, CK_OBJECT_HANDLE_PT
}
ASSERT(bobj->obj.id != 0);
- *id = bobj->obj.id;
+ *obj = &(bobj->obj);
return CKR_OK;
}
CK_RV
-ckcapi_builtin_find_all(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,
- CK_ULONG count, CkCapiArray* arr)
+ckcapi_builtin_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR match,
+ CK_ULONG count, CkCapiArray* arr)
{
- CK_OBJECT_HANDLE obj;
+ CkCapiObject* obj;
CkCapiObjectData objdata;
CK_RV ret = CKR_OK;
CK_ULONG i;
diff --git a/ckcapi-cert.c b/ckcapi-cert.c
index 0162983..887fefb 100644
--- a/ckcapi-cert.c
+++ b/ckcapi-cert.c
@@ -15,6 +15,18 @@
#define USE_ENCODINGS (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
+/* All the stores we look in for certificates, in this order */
+static const char* CERT_STORES[] = {
+ "My",
+ "AddressBook",
+ "CA",
+ "Root",
+ "Trust",
+ "TrustedPeople",
+ "AuthRoot",
+ NULL
+};
+
typedef struct _CertObject
{
CkCapiObject obj;
@@ -33,37 +45,6 @@ typedef struct _CertObject
}
CertObject;
-typedef struct _CertUnique
-{
- int otype;
- BYTE key[1];
-}
-CertUnique;
-
-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_ATTRIBUTE_TYPE_INVALID;
-
- if(!val)
- {
- *len = cb;
- return CKR_OK;
- }
-
- if(cb > *len)
- {
- *len = cb;
- return CKR_BUFFER_TOO_SMALL;
- }
-
- *len = cb;
- memcpy(val, data, cb);
- return CKR_OK;
-}
-
static CK_RV
cert_bool_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
CK_VOID_PTR data, CK_ULONG_PTR len)
@@ -114,7 +95,7 @@ cert_bool_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
return CKR_ATTRIBUTE_TYPE_INVALID;
};
- return copy_static_data(data, len, &val, sizeof(CK_BBOOL));
+ return ckcapi_return_data(data, len, &val, sizeof(CK_BBOOL));
}
static CK_RV
@@ -163,12 +144,12 @@ cert_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
return CKR_BUFFER_TOO_SMALL;
}
- return copy_static_data(data, len, &val, sizeof(CK_ULONG));
+ return ckcapi_return_data(data, len, &val, sizeof(CK_ULONG));
}
-static CK_RV
-cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
- CK_VOID_PTR data, CK_ULONG_PTR len)
+CK_RV
+ckcapi_cert_get_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
+ CK_VOID_PTR data, CK_ULONG_PTR len)
{
PCCERT_CONTEXT cert = (PCCERT_CONTEXT)obj;
DWORD err;
@@ -258,7 +239,7 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
* directly.
*/
case CKA_SUBJECT:
- return copy_static_data(data, len, cert->pCertInfo->Subject.pbData,
+ return ckcapi_return_data(data, len, cert->pCertInfo->Subject.pbData,
cert->pCertInfo->Subject.cbData);
/*
@@ -268,7 +249,7 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
* directly.
*/
case CKA_ISSUER:
- return copy_static_data(data, len, cert->pCertInfo->Issuer.pbData,
+ return ckcapi_return_data(data, len, cert->pCertInfo->Issuer.pbData,
cert->pCertInfo->Issuer.cbData);
/*
@@ -298,7 +279,7 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
* We use CAPI's CERT_CONTEXT pbCertEncoded field directly.
*/
case CKA_VALUE:
- return copy_static_data(data, len, cert->pbCertEncoded,
+ return ckcapi_return_data(data, len, cert->pbCertEncoded,
cert->cbCertEncoded);
/*
@@ -372,13 +353,13 @@ cert_release(void* data)
static const CkCapiObjectDataVtable cert_objdata_vtable = {
cert_bool_attribute,
cert_ulong_attribute,
- cert_bytes_attribute,
+ ckcapi_cert_get_bytes_attribute,
cert_date_attribute,
cert_release,
};
static CK_RV
-cert_load(CkCapiObject* obj, CkCapiObjectData* objdata)
+cert_load_data(CkCapiSession* sess, CkCapiObject* obj, CkCapiObjectData* objdata)
{
CertObject* cobj = (CertObject*)obj;
HCERTSTORE store;
@@ -419,6 +400,10 @@ cert_load(CkCapiObject* obj, CkCapiObjectData* objdata)
return ckcapi_winerr_to_ckr(GetLastError());
}
+ /*
+ * Important: The trust stuff depends on the objdata value of a
+ * certificate object is a CERT_CONTEXT pointer.
+ */
objdata->data = (void*)cert;
objdata->data_funcs = cert_objdata_vtable;
return CKR_OK;
@@ -434,7 +419,7 @@ cert_object_release(void* data)
}
static const CkCapiObjectVtable cert_object_vtable = {
- cert_load,
+ cert_load_data,
cert_object_release,
};
@@ -500,9 +485,9 @@ clear_object_data_for_store(CkCapiSession* sess, CkCapiObject* obj,
ckcapi_session_clear_object_data(sess, obj);
}
-CK_RV
-ckcapi_cert_find_in_store(CkCapiSession* sess, const char* store_name,
- CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr)
+static CK_RV
+find_in_store(CkCapiSession* sess, const char* store_name,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr)
{
PCCERT_CONTEXT cert = NULL;
CkCapiObject* obj;
@@ -549,10 +534,73 @@ ckcapi_cert_find_in_store(CkCapiSession* sess, const char* store_name,
CertFreeCertificateContext((PCCERT_CONTEXT)objdata.data);
}
- ckcapi_array_append(arr, obj->id);
+ ckcapi_array_append(arr, obj);
+ }
+ }
+
+ ASSERT(store);
+ CertCloseStore(store, 0);
+
+ return ret;
+}
+
+static CK_RV
+match_in_store(CkCapiSession* sess, const char* store_name, PCERT_INFO info,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr)
+{
+ PCCERT_CONTEXT cert = NULL;
+ CkCapiObject* 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);
+ }
+
+ cert = CertGetSubjectCertificateFromStore(store, USE_ENCODINGS, info);
+ if(cert == NULL)
+ {
+ err = GetLastError();
+
+ /* Certificate not found, we don't care */
+ if(err == CRYPT_E_NOT_FOUND)
+ return CKR_OK;
+ else
+ return ckcapi_winerr_to_ckr(err);
+ }
+
+ /* Match the certificate */
+ objdata.data = (void*)cert;
+ objdata.data_funcs = cert_objdata_vtable;
+
+ if(ckcapi_object_data_match(&objdata, match, count))
+ {
+ ret = register_cert_object(sess, store_name, cert, &obj);
+ if(ret == CKR_OK)
+ {
+ ASSERT(obj);
+
+ /* Store away the object data for performance reasons */
+ ret = ckcapi_session_set_object_data(sess, obj, &objdata);
+ if(ret == CKR_OK)
+ ckcapi_array_append(arr, obj);
}
}
+ if(ret != CKR_OK && cert)
+ CertFreeCertificateContext(cert);
+
+
ASSERT(store);
CertCloseStore(store, 0);
@@ -560,23 +608,75 @@ ckcapi_cert_find_in_store(CkCapiSession* sess, const char* store_name,
}
CK_RV
-ckcapi_cert_find_all(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,
- CK_ULONG count, CkCapiArray* arr)
+ckcapi_cert_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR match,
+ CK_ULONG count, CkCapiArray* arr)
{
+ CRYPT_INTEGER_BLOB* serial = NULL;
+ CERT_INFO info;
CK_RV ret;
+ BOOL specific;
+ CK_ULONG i;
+ DWORD size;
+
+ /* We only have certificates here */
+ if(cls != CKO_CERTIFICATE && cls != CKO_ANY)
+ return CKR_OK;
+
+ /*
+ * See if we have a issuer and serial number for a
+ * specific certificate to find.
+ */
+ memset(&info, 0, sizeof(info));
+
+ for(i = 0; i < count; ++i)
+ {
+ if(!match[i].pValue || !match[i].ulValueLen)
+ continue;
+
+ if(match[i].type == CKA_ISSUER)
+ {
+ info.Issuer.cbData = match[i].ulValueLen;
+ info.Issuer.pbData = match[i].pValue;
+ }
+ else if(!serial && match[i].type == CKA_SERIAL_NUMBER)
+ {
+ if(!CryptDecodeObject(USE_ENCODINGS, X509_MULTI_BYTE_INTEGER,
+ match[i].pValue, match[i].ulValueLen, 0, NULL, &size))
+ {
+ continue;
+ }
+
+ serial = calloc(1, size);
+ if(!CryptDecodeObject(USE_ENCODINGS, X509_MULTI_BYTE_INTEGER,
+ match[i].pValue, match[i].ulValueLen, 0, serial, &size))
+ continue;
+
+ ASSERT(serial->cbData);
+ ASSERT(serial->pbData);
+
+ info.SerialNumber.cbData = serial->cbData;
+ info.SerialNumber.pbData = serial->pbData;
+ }
+ }
+
+ specific = info.SerialNumber.cbData && info.Issuer.cbData;
+
+ for(i = 0; CERT_STORES[i]; ++i)
+ {
+ /* Match a specific certificate */
+ if(specific)
+ ret = match_in_store(sess, CERT_STORES[i], &info, match, count, arr);
+
+ /* Match any ol certificate */
+ else
+ ret = find_in_store(sess, CERT_STORES[i], match, count, arr);
+
+ if(ret != CKR_OK)
+ break;
+ }
+
+ if(serial)
+ free(serial);
- 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 49da8eb..4bc0ce1 100644
--- a/ckcapi-object.c
+++ b/ckcapi-object.c
@@ -1,6 +1,8 @@
#include "ckcapi.h"
+#include "pkcs11/pkcs11n.h"
+
#include <memory.h>
#include <wtypes.h>
@@ -208,6 +210,14 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type)
case CKA_BITS_PER_PIXEL:
case CKA_MECHANISM_TYPE:
case CKA_JAVA_MIDP_SECURITY_DOMAIN:
+ case CKA_TRUST_SERVER_AUTH:
+ case CKA_TRUST_CLIENT_AUTH:
+ case CKA_TRUST_CODE_SIGNING:
+ case CKA_TRUST_EMAIL_PROTECTION:
+ case CKA_TRUST_IPSEC_END_SYSTEM:
+ case CKA_TRUST_IPSEC_TUNNEL:
+ case CKA_TRUST_IPSEC_USER:
+ case CKA_TRUST_TIME_STAMPING:
return DATA_ULONG;
// CK_BBOOL attribute types
@@ -234,6 +244,7 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type)
case CKA_RESET_ON_INIT:
case CKA_HAS_RESET:
case CKA_COLOR:
+ case CKA_TRUST_STEP_UP_APPROVED:
return DATA_BOOL;
// Raw or string data
@@ -272,6 +283,8 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type)
case CKA_REQUIRED_CMS_ATTRIBUTES:
case CKA_DEFAULT_CMS_ATTRIBUTES:
case CKA_SUPPORTED_CMS_ATTRIBUTES:
+ case CKA_CERT_SHA1_HASH:
+ case CKA_CERT_MD5_HASH:
return DATA_BYTES;
// CK_DATE data
@@ -284,6 +297,7 @@ attribute_data_type(CK_ATTRIBUTE_TYPE type)
case CKA_ALLOWED_MECHANISMS:
case CKA_UNWRAP_TEMPLATE:
default:
+ DBG(("unknown attribute type: %x\n", type));
return DATA_UNKNOWN;
};
}
@@ -331,9 +345,15 @@ ckcapi_object_data_match_attr(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR match)
break;
};
+ /* Unrecognized attribute */
+ if(rv == CKR_ATTRIBUTE_TYPE_INVALID)
+ return CK_FALSE;
+
/* Value is longer than this one */
if(rv == CKR_BUFFER_TOO_SMALL)
return CK_FALSE;
+
+ /* All other errors */
if(rv != CKR_OK)
return CK_FALSE;
@@ -413,6 +433,7 @@ ckcapi_object_data_get_attrs(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attrs,
/* Attribute doesn't exist */
else if(rv == CKR_ATTRIBUTE_TYPE_INVALID)
{
+ DBG(("O%d: attribute not found: 0x%08x", objdata->object, attrs[i].type));
attrs[i].ulValueLen = (CK_ULONG)-1;
}
diff --git a/ckcapi-session.c b/ckcapi-session.c
index 9f9a6e6..8d00316 100644
--- a/ckcapi-session.c
+++ b/ckcapi-session.c
@@ -349,17 +349,6 @@ ckcapi_session_close_all()
*/
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);
-}
-
-CK_RV
ckcapi_session_get_object_data(CkCapiSession* sess, CkCapiObject* obj,
CkCapiObjectData** objdata)
{
@@ -384,12 +373,16 @@ ckcapi_session_get_object_data(CkCapiSession* sess, CkCapiObject* obj,
return CKR_HOST_MEMORY;
newdata->object = id;
- ret = (obj->obj_funcs.load_data)(obj, newdata);
+ ret = (obj->obj_funcs.load_data)(sess, obj, newdata);
if(ret != CKR_OK) {
free(newdata);
return ret;
}
+ newdata->object = id;
+ ASSERT(newdata->data);
+ ASSERT(newdata->data_funcs.release);
+
if(!ckcapi_hash_set(sess->object_data, &newdata->object,
sizeof(newdata->object), newdata)) {
object_data_release(newdata);
@@ -517,28 +510,25 @@ static CK_RV
gather_objects(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,
CK_ULONG count, CkCapiArray* arr)
{
- CK_OBJECT_CLASS ocls = CK_INVALID_HANDLE;
+ CK_OBJECT_CLASS ocls = CKO_ANY;
CK_RV ret = CKR_OK;
- /* TODO: Reenable this once we have trust worked out
- ret = ckcapi_builtin_find_all(sess, match, count, arr);
+ get_ulong_attribute(CKA_CLASS, match, count, &ocls);
+
+ /* Search for builtins */
+ ret = ckcapi_builtin_find(sess, ocls, match, count, arr);
if(ret != CKR_OK)
return ret;
- */
- 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;
- };
+ /* Search for certificates */
+ ret = ckcapi_cert_find(sess, ocls, match, count, arr);
+ if(ret != CKR_OK)
+ return ret;
+
+ /* Search through trust objects */
+ ret = ckcapi_trust_find(sess, ocls, match, count, arr);
+ if(ret != CKR_OK)
+ return ret;
return ret;
}
@@ -555,10 +545,10 @@ cleanup_find_operation(CkCapiSession* sess)
}
void
-purge_duplicate_ulongs(CkCapiArray* arr)
+purge_duplicate_objects(CkCapiArray* arr)
{
CkCapiHash* checks;
- CK_ULONG* v;
+ CkCapiObject* v;
size_t i;
checks = ckcapi_hash_new();
@@ -567,15 +557,15 @@ purge_duplicate_ulongs(CkCapiArray* arr)
for(i = 0; i < arr->len; )
{
- v = &ckcapi_array_index(arr, CK_ULONG, i);
- if(ckcapi_hash_get(checks, v, sizeof(CK_ULONG)))
+ v = ckcapi_array_index(arr, CkCapiObject*, i);
+ if(ckcapi_hash_get(checks, &v, sizeof(CkCapiObject*)))
{
ckcapi_array_remove_index(arr, i);
/* Look at same i again */
}
else
{
- if(!ckcapi_hash_set(checks, v, sizeof(CK_ULONG), v))
+ if(!ckcapi_hash_set(checks, &v, sizeof(CkCapiObject*), &v))
break;
++i;
}
@@ -597,7 +587,7 @@ ckcapi_session_find_init(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,
if(sess->operation_type != OPERATION_NONE)
return CKR_OPERATION_ACTIVE;
- arr = ckcapi_array_new(0, 1, sizeof(CK_OBJECT_HANDLE));
+ arr = ckcapi_array_new(0, 1, sizeof(CkCapiObject*));
if(!arr)
return CKR_HOST_MEMORY;
@@ -609,7 +599,7 @@ ckcapi_session_find_init(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,
}
/* Cleanup all duplicates in the array */
- purge_duplicate_ulongs(arr);
+ purge_duplicate_objects(arr);
sess->operation_type = OPERATION_FIND;
sess->operation_data = arr;
@@ -641,7 +631,7 @@ ckcapi_session_find(CkCapiSession* sess, CK_OBJECT_HANDLE_PTR objects,
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);
+ objects[i] = ckcapi_array_index(arr, CkCapiObject*, i)->id;
ckcapi_array_remove_range(arr, 0, *object_count);
return CKR_OK;
diff --git a/ckcapi-trust.c b/ckcapi-trust.c
new file mode 100644
index 0000000..c49a2de
--- /dev/null
+++ b/ckcapi-trust.c
@@ -0,0 +1,437 @@
+
+#include "ckcapi.h"
+#include "x509-usages.h"
+
+#include "pkcs11/pkcs11n.h"
+
+#include <wincrypt.h>
+
+typedef struct _TrustObject
+{
+ CkCapiObject obj;
+
+ /* Together these form the unique key. Must be contiguous */
+ unsigned int otype;
+ CK_OBJECT_HANDLE cert_obj;
+}
+TrustObject;
+
+typedef struct _TrustData
+{
+ PCCERT_CONTEXT cert;
+ CTL_USAGE* usage;
+}
+TrustData;
+
+static CK_ULONG
+has_usage(TrustData* trust_data, const char* oid)
+{
+ CTL_USAGE* usage = trust_data->usage;
+ DWORD i;
+
+ /* No usages, means anything goes */
+ if(usage == NULL)
+ return CKT_NETSCAPE_TRUSTED_DELEGATOR;
+
+ for(i = 0; i < usage->cUsageIdentifier; ++i)
+ {
+ if(usage->rgpszUsageIdentifier[i] &&
+ strcmp(oid, usage->rgpszUsageIdentifier[i]) == 0)
+ return CKT_NETSCAPE_TRUSTED_DELEGATOR;
+ }
+
+ /* TODO: What's the correct thing to return here? */
+ return CKT_NETSCAPE_VALID_DELEGATOR;
+}
+
+static CK_RV
+trust_bool_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
+ CK_VOID_PTR data, CK_ULONG_PTR len)
+{
+ CK_BBOOL val;
+
+ ASSERT(obj);
+
+ switch(type)
+ {
+ /*
+ * Resides on the token
+ * - Always true for CAPI objects.
+ */
+ case CKA_TOKEN:
+ val = CK_TRUE;
+ break;
+
+ /*
+ * Private vs. Public object.
+ * - Always false for certificates.
+ */
+ case CKA_PRIVATE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * If object can be modified.
+ * TODO: This needs to be set to yes once we get change support.
+ */
+ case CKA_MODIFIABLE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * TODO: Figure out what this is.
+ */
+ case CKA_TRUST_STEP_UP_APPROVED:
+ val = CK_FALSE;
+ break;
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+
+ return ckcapi_return_data(data, len, &val, sizeof(CK_BBOOL));
+}
+
+static CK_RV
+trust_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
+ CK_VOID_PTR data, CK_ULONG_PTR len)
+{
+ TrustData* trust_data = (TrustData*)obj;
+ CK_ULONG val;
+
+ ASSERT(obj);
+
+ switch(type)
+ {
+
+ /*
+ * Object class.
+ * - Always CKO_NETSCAPE_TRUST for netscape trust
+ */
+ case CKA_CLASS:
+ val = CKO_NETSCAPE_TRUST;
+ break;
+
+ /*
+ * Various trust flags
+ */
+ case CKA_TRUST_SERVER_AUTH:
+ val = has_usage(trust_data, X509_USAGE_SERVER_AUTH);
+ break;
+ case CKA_TRUST_CLIENT_AUTH:
+ val = has_usage(trust_data, X509_USAGE_CLIENT_AUTH);
+ break;
+ case CKA_TRUST_CODE_SIGNING:
+ val = has_usage(trust_data, X509_USAGE_CODE_SIGNING);
+ break;
+ case CKA_TRUST_EMAIL_PROTECTION:
+ val = has_usage(trust_data, X509_USAGE_EMAIL);
+ break;
+ case CKA_TRUST_IPSEC_END_SYSTEM:
+ val = has_usage(trust_data, X509_USAGE_IPSEC_ENDPOINT);
+ break;
+ case CKA_TRUST_IPSEC_TUNNEL:
+ val = has_usage(trust_data, X509_USAGE_IPSEC_TUNNEL);
+ break;
+ case CKA_TRUST_IPSEC_USER:
+ val = has_usage(trust_data, X509_USAGE_IPSEC_USER);
+ break;
+ case CKA_TRUST_TIME_STAMPING:
+ val = has_usage(trust_data, X509_USAGE_TIME_STAMPING);
+ break;
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+
+ if(*len < sizeof(CK_ULONG))
+ {
+ *len = sizeof(CK_ULONG);
+ return CKR_BUFFER_TOO_SMALL;
+ }
+
+ return ckcapi_return_data(data, len, &val, sizeof(CK_ULONG));
+}
+
+static CK_RV
+trust_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
+ CK_VOID_PTR data, CK_ULONG_PTR len)
+{
+ TrustData* trust_data = (TrustData*)obj;
+ ASSERT(obj);
+
+ switch(type)
+ {
+ /*
+ * Forward these through to the certificate itself.
+ */
+ case CKA_SUBJECT:
+ case CKA_ISSUER:
+ case CKA_SERIAL_NUMBER:
+ case CKA_LABEL:
+ ASSERT(trust_data->cert);
+ return ckcapi_cert_get_bytes_attribute((void*)(trust_data->cert),
+ type, data, len);
+
+ /*
+ * TODO: These should probably be implemented
+ */
+ case CKA_CERT_MD5_HASH:
+ case CKA_CERT_SHA1_HASH:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ };
+
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+}
+
+static CK_RV
+trust_date_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
+ CK_VOID_PTR data, CK_ULONG_PTR len)
+{
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+}
+
+static void
+trust_release(void* data)
+{
+ TrustData* trust_data = (TrustData*)data;
+ ASSERT(trust_data);
+
+ ASSERT(trust_data->cert);
+ CertFreeCertificateContext(trust_data->cert);
+
+ if(trust_data->usage)
+ free(trust_data->usage);
+
+ free(trust_data);
+}
+
+static const CkCapiObjectDataVtable trust_objdata_vtable = {
+ trust_bool_attribute,
+ trust_ulong_attribute,
+ trust_bytes_attribute,
+ trust_date_attribute,
+ trust_release,
+};
+
+static CK_RV
+parse_usage(TrustData* trust_data)
+{
+ DWORD size, usize, err;
+ CTL_USAGE* usage;
+ void* buf;
+
+ ASSERT(!trust_data->usage);
+
+ /* Get the size of the usage property */
+ if(!CertGetCertificateContextProperty(trust_data->cert, CERT_CTL_USAGE_PROP_ID,
+ NULL, &size))
+ {
+ err = GetLastError();
+
+ /* No usage data is not an error */
+ if(err == CRYPT_E_NOT_FOUND)
+ return CKR_OK;
+ return ckcapi_winerr_to_ckr(err);
+ }
+
+ /* Now get the actual usage property */
+ buf = _alloca(size);
+ if(!CertGetCertificateContextProperty(trust_data->cert, CERT_CTL_USAGE_PROP_ID,
+ buf, &size))
+ {
+ err = GetLastError();
+ if(err == CRYPT_E_NOT_FOUND)
+ return CKR_OK;
+ return ckcapi_winerr_to_ckr(err);
+ }
+
+ /* Get the decoded size of the usage property */
+ if(!CryptDecodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
+ buf, size, 0, NULL, &usize))
+ return ckcapi_winerr_to_ckr(GetLastError());
+
+ /* Allocate and decode it */
+ usage = (CTL_USAGE*)calloc(1, usize);
+ if(!usage)
+ return CKR_HOST_MEMORY;
+ if(!CryptDecodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
+ buf, size, 0, buf, &usize))
+ {
+ free(usage);
+ return ckcapi_winerr_to_ckr(GetLastError());
+ }
+
+ trust_data->usage = usage;
+ return CKR_OK;
+}
+
+static CK_RV
+trust_load_data(CkCapiSession* sess, CkCapiObject* obj, CkCapiObjectData* objdata)
+{
+ TrustObject* tobj = (TrustObject*)obj;
+ TrustData* trust_data;
+ CkCapiObjectData* certdata;
+ CK_RV ret;
+
+ ASSERT(tobj);
+ ASSERT(objdata);
+
+ /* Get the raw data for the certificate */
+ ret = ckcapi_session_get_object_data_for(sess, tobj->cert_obj, &certdata);
+ if(ret != CKR_OK)
+ return ret;
+
+ trust_data = (TrustData*)calloc(1, sizeof(TrustData));
+ if(!trust_data)
+ return CKR_HOST_MEMORY;
+
+ ASSERT(certdata->data);
+ trust_data->cert = certdata->data;
+
+ /* Dig up the usage data */
+ ret = parse_usage(trust_data);
+ if(ret != CKR_OK)
+ {
+ free(trust_data);
+ return ret;
+ }
+
+ /* And keep a reference to the certificate */
+ trust_data->cert = CertDuplicateCertificateContext((PCCERT_CONTEXT)(certdata->data));
+
+ objdata->data = trust_data;
+ objdata->data_funcs = trust_objdata_vtable;
+
+ return CKR_OK;
+}
+
+
+static void
+trust_object_release(void* data)
+{
+ TrustObject* tobj = (TrustObject*)data;
+ ASSERT(tobj);
+ free(tobj);
+}
+
+static const CkCapiObjectVtable trust_object_vtable = {
+ trust_load_data,
+ trust_object_release,
+};
+
+static CK_RV
+register_trust_object(CkCapiSession* sess, CkCapiObject* cert, CkCapiObject** obj)
+{
+ TrustObject* tobj;
+ CK_RV ret;
+
+ tobj = calloc(sizeof(TrustObject), 1);
+ if(!tobj)
+ return CKR_HOST_MEMORY;
+
+ tobj->otype = OBJECT_TRUST;
+ tobj->cert_obj = cert->id;
+
+ tobj->obj.id = 0;
+ tobj->obj.obj_funcs = trust_object_vtable;
+ tobj->obj.unique_key = UNIQUE_KEY_AT(tobj, otype);
+ tobj->obj.unique_len = UNIQUE_KEY_LEN(tobj, otype, cert_obj);
+
+ ret = ckcapi_object_register(sess, &(tobj->obj));
+ if(ret != CKR_OK)
+ {
+ free(tobj);
+ return ret;
+ }
+
+ ASSERT(tobj->obj.id != 0);
+ *obj = &(tobj->obj);
+
+ return CKR_OK;
+}
+
+static CK_RV
+list_matching_certificates(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,
+ CK_ULONG count, CkCapiArray* 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)
+ {
+ /*
+ * These are the attributes that tie a certificate
+ * to trust object, so try match certs with these
+ */
+ if(match[i].type == CKA_ISSUER ||
+ match[i].type == CKA_SERIAL_NUMBER)
+ {
+ 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 ckcapi_cert_find(sess, CKO_CERTIFICATE, search, n_search, arr);
+}
+
+CK_RV
+ckcapi_trust_find(CkCapiSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr)
+{
+ CkCapiObject* obj;
+ CkCapiObject* certobj;
+ CkCapiObjectData* objdata;
+ CkCapiArray* certarr;
+ CK_RV ret = CKR_OK;
+ CK_ULONG i;
+
+ if(cls != CKO_NETSCAPE_TRUST)
+ return CKR_OK;
+
+ /* Get a list of all certificates */
+ certarr = ckcapi_array_new(0, 1, sizeof(CkCapiObject*));
+ if(!certarr)
+ return CKR_HOST_MEMORY;
+ ret = list_matching_certificates(sess, match, count, certarr);
+
+ /* Now match each of them against our criteria */
+ if(ret == CKR_OK)
+ {
+ for(i = 0; i < certarr->len; ++i)
+ {
+ certobj = ckcapi_array_index(certarr, CkCapiObject*, i);
+ ASSERT(certobj);
+
+ /* We'll register a trust object for any loaded certificate */
+ ret = register_trust_object(sess, certobj, &obj);
+ if(ret != CKR_OK)
+ break;
+
+ ASSERT(obj);
+
+ ret = ckcapi_session_get_object_data(sess, obj, &objdata);
+ if(ret != CKR_OK)
+ break;
+
+ /* Only return new object if it matches */
+ if(ckcapi_object_data_match(objdata, match, count))
+ ckcapi_array_append(arr, obj);
+ }
+ }
+
+ ckcapi_array_free(certarr, TRUE);
+ return ret;
+}
diff --git a/ckcapi.c b/ckcapi.c
index 0bed282..f0c4629 100644
--- a/ckcapi.c
+++ b/ckcapi.c
@@ -112,6 +112,34 @@ ckcapi_winerr_to_ckr(DWORD werr)
}
+CK_RV
+ckcapi_return_data(CK_VOID_PTR dst, CK_ULONG_PTR dlen,
+ CK_VOID_PTR src, DWORD slen)
+{
+ // TODO: This check should probably go elsewhere
+ if(slen == 0)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ /* Just asking for the length */
+ if(!dst)
+ {
+ *dlen = slen;
+ return CKR_OK;
+ }
+
+ /* Buffer is too short */
+ if(slen > *dlen)
+ {
+ *dlen = slen;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+
+ *dlen = slen;
+ memcpy(dst, src, slen);
+ return CKR_OK;
+}
+
+
/* ---------------------------------------------------------------- */
static CK_RV
diff --git a/ckcapi.dsp b/ckcapi.dsp
index d81ae3a..6d73e54 100644
--- a/ckcapi.dsp
+++ b/ckcapi.dsp
@@ -108,6 +108,10 @@ SOURCE=".\ckcapi-session.c"
# End Source File
# Begin Source File
+SOURCE=".\ckcapi-trust.c"
+# End Source File
+# Begin Source File
+
SOURCE=".\ckcapi-util.c"
# End Source File
# Begin Source File
diff --git a/ckcapi.dsw b/ckcapi.dsw
index 7f71040..a6cb239 100644
--- a/ckcapi.dsw
+++ b/ckcapi.dsw
@@ -3,7 +3,19 @@ Microsoft Developer Studio Workspace File, Format Version 6.00
###############################################################################
-Project: "cryptoki_capi"=".\cryptoki_capi.dsp" - Package Owner=<4>
+Project: "cryptoki_capi"=".\ckcapi.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "sandbox"=".\sandbox\sandbox.dsp" - Package Owner=<4>
Package=<5>
{{{
diff --git a/ckcapi.h b/ckcapi.h
index d6ee27b..d3ead45 100644
--- a/ckcapi.h
+++ b/ckcapi.h
@@ -21,6 +21,9 @@ struct _CkCapiSession;
typedef struct _CkCapiObject CkCapiObject;
typedef struct _CkCapiSession CkCapiSession;
+/* Represents 'any' class in searches */
+#define CKO_ANY CK_INVALID_HANDLE
+
/* ------------------------------------------------------------------
* cryptoki-capi.c
*/
@@ -33,6 +36,9 @@ void ckcapi_lock_global(void);
void ckcapi_unlock_global(void);
CK_RV ckcapi_winerr_to_ckr (DWORD werr);
+CK_RV ckcapi_return_data(CK_VOID_PTR dst, CK_ULONG_PTR dlen,
+ CK_VOID_PTR src, DWORD slen);
+
/* object data ------------------- */
typedef CK_RV (*CkCapiGetAttribute)(void* obj, CK_ATTRIBUTE_TYPE type,
@@ -126,16 +132,18 @@ void ckcapi_session_enum_object_data (CkCapiSession* sess, CkCapiEnumObjectData
* ckcapi-object.c
*/
-/* For operation_type in CkCapiSession */
+/* Used internally to guarantee uniqueness between object types */
enum
{
OBJECT_CERT = 1,
- OBJECT_BUILTIN = 2
+ OBJECT_BUILTIN = 2,
+ OBJECT_TRUST = 3
};
typedef CK_RV (*CkCapiPurge)(struct _CkCapiObject* obj);
-typedef CK_RV (*CkCapiLoadData)(struct _CkCapiObject* obj, CkCapiObjectData* objdata);
+typedef CK_RV (*CkCapiLoadData)(CkCapiSession* sess, struct _CkCapiObject* obj,
+ CkCapiObjectData* objdata);
typedef struct _CkCapiObjectVtable
{
@@ -176,6 +184,8 @@ struct _CkCapiObject
#define DBGO(obj, msg) \
ckcapi_debug("O%d: %s", (obj) ? (obj)->id : 0, (msg))
+#define DBGOD(objdata, msg) \
+ ckcapi_debug("O%d: %s", (objdata) ? (objdata)->obj : 0, (msg))
CK_OBJECT_HANDLE ckcapi_object_get_max_handle (void);
@@ -199,18 +209,38 @@ CK_RV ckcapi_object_data_get_attrs (CkCapiObjectData* objdata, CK_ATTRIBUTE_P
* 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 (CkCapiSession* sess, CK_OBJECT_CLASS cls,
+ 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);
+CK_RV ckcapi_cert_find_specific (CkCapiSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR issuer, CK_ATTRIBUTE_PTR serial,
+ CK_OBJECT_HANDLE_PTR obj);
+
+/* Called by trust stuff */
+CK_RV ckcapi_cert_get_bytes_attribute (void* cert, CK_ATTRIBUTE_TYPE type,
+ CK_VOID_PTR data, CK_ULONG_PTR len);
/* -------------------------------------------------------------------
* ckcapi-builtin.c
*/
-CK_RV ckcapi_builtin_find_all (CkCapiSession* sess, CK_ATTRIBUTE_PTR match,
- CK_ULONG count, CkCapiArray* arr);
+CK_RV ckcapi_builtin_find (CkCapiSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count,
+ CkCapiArray* arr);
+
+/* -------------------------------------------------------------------
+ * ckcapi-trust.c
+ */
+
+CK_RV ckcapi_trust_find (CkCapiSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count,
+ CkCapiArray* arr);
+
+CK_RV ckcapi_trust_find_specific (CkCapiSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR issuer, CK_ATTRIBUTE_PTR serial,
+ CK_OBJECT_HANDLE_PTR obj);
+
#endif /* CRYPTOKI_CAPI_H */
diff --git a/x509-usages.h b/x509-usages.h
new file mode 100644
index 0000000..d63c8bb
--- /dev/null
+++ b/x509-usages.h
@@ -0,0 +1,39 @@
+#ifndef _X509_USAGES_H_
+#define _X509_USAGES_H_
+
+
+#define X509_USAGE_SERVER_AUTH "1.3.6.1.5.5.7.3.1"
+#define X509_USAGE_CLIENT_AUTH "1.3.6.1.5.5.7.3.2"
+#define X509_USAGE_CODE_SIGNING "1.3.6.1.5.5.7.3.3"
+#define X509_USAGE_EMAIL "1.3.6.1.5.5.7.3.4"
+#define X509_USAGE_TIME_STAMPING "1.3.6.1.5.5.7.3.8"
+#define X509_USAGE_IPSEC_ENDPOINT "1.3.6.1.5.5.7.3.5"
+#define X509_USAGE_IPSEC_TUNNEL "1.3.6.1.5.5.7.3.6"
+#define X509_USAGE_IPSEC_USER "1.3.6.1.5.5.7.3.7"
+#define X509_USAGE_IKE_INTERMEDIATE "1.3.6.1.5.5.8.2.2"
+
+
+#define MS_USAGE_TRUST_LIST_SIGNING "1.3.6.1.4.1.311.10.3.1"
+#define MS_USAGE_TIME_STAMPING "1.3.6.1.4.1.311.10.3.2"
+#define MS_USAGE_EFS "1.3.6.1.4.1.311.10.3.4"
+#define MS_USAGE_DRIVER_VERIFICATION "1.3.6.1.4.1.311.10.3.5"
+#define MS_USAGE_SYSTEM_VERIFICATION "1.3.6.1.4.1.311.10.3.6"
+#define MS_USAGE_OEM_VERIFICATION "1.3.6.1.4.1.311.10.3.7"
+#define MS_USAGE_EMBEDDED_VERIFICATION "1.3.6.1.4.1.311.10.3.8"
+#define MS_USAGE_KEY_PACK "1.3.6.1.4.1.311.10.6.1"
+#define MS_USAGE_LICENSE_SERVER "1.3.6.1.4.1.311.10.6.2"
+#define MS_USAGE_SMART_CARD "1.3.6.1.4.1.311.20.2.2"
+#define MS_USAGE_DIGITAL_RIGHTS "1.3.6.1.4.1.311.10.5.1"
+#define MS_USAGE_QUALIFIED_SUBORDINATION "1.3.6.1.4.1.311.10.3.10"
+#define MS_USAGE_KEY_RECOVERY "1.3.6.1.4.1.311.10.3.11"
+#define MS_USAGE_DOCUMENT_SIGNING "1.3.6.1.4.1.311.10.3.12"
+#define MS_USAGE_FILE_RECOVERY "1.3.6.1.4.1.311.10.3.4.1"
+#define MS_USAGE_ROOT_SIGNER_LIST "1.3.6.1.4.1.311.10.3.9"
+#define MS_USAGE_APPLICATION_POLICIES "1.3.6.1.4.1.311.10.12.1"
+#define MS_USAGE_AD_EMAIL_REPLICATION "1.3.6.1.4.1.311.21.19"
+#define MS_USAGE_CERTIFICATE_REQUEST_AGENT "1.3.6.1.4.1.311.20.2.1"
+#define MS_USAGE_KEY_RECOVERY_AGENT "1.3.6.1.4.1.311.21.6"
+#define MS_USAGE_CA_ENCRYPTION_CERTIFICATE "1.3.6.1.4.1.311.21.5"
+#define MS_USAGE_LIFETIME_SIGNING "1.3.6.1.4.1.311.10.3.13"
+
+#endif /* _X509_USAGES_H_ */