#include "ckcapi.h" #include "pkcs11/pkcs11n.h" static const CK_BBOOL ck_true = CK_TRUE; static const CK_BBOOL ck_false = CK_FALSE; static const CK_OBJECT_CLASS cko_netscape_builtin_root_list = CKO_NETSCAPE_BUILTIN_ROOT_LIST; static const char ck_root_label[] = "Windows Certificate Roots"; #define CK_END_LIST (CK_ULONG)-1 static const CK_ATTRIBUTE builtin_root[] = { { CKA_TOKEN, (void*)&ck_true, sizeof(CK_BBOOL) }, { CKA_CLASS, (void*)&cko_netscape_builtin_root_list, sizeof(CK_OBJECT_CLASS) }, { CKA_PRIVATE, (void*)&ck_false, sizeof(CK_BBOOL) }, { CKA_MODIFIABLE, (void*)&ck_false, sizeof(CK_BBOOL) }, { CKA_LABEL, (void*)ck_root_label, sizeof(ck_root_label) }, { CK_END_LIST, NULL, 0 } }; static const CK_ATTRIBUTE_PTR all_builtins[] = { (CK_ATTRIBUTE_PTR)&builtin_root, NULL, }; static CK_ULONG num_builtins = 0; typedef struct _BuiltinObject { CkCapiObject obj; /* Together these form the unique key. Must be contiguous */ unsigned int otype; CK_ULONG builtin_index; } BuiltinObject; static CK_RV builtin_attribute(void* obj, CK_ATTRIBUTE_TYPE type, CK_VOID_PTR data, CK_ULONG_PTR len) { CK_ATTRIBUTE_PTR builtin = (CK_ATTRIBUTE_PTR)obj; ASSERT(len); ASSERT(obj); while(builtin->type != CK_END_LIST) { if(builtin->type == type) { if(builtin->ulValueLen == 0) return CKR_ATTRIBUTE_TYPE_INVALID; if(!data) { *len = builtin->ulValueLen; return CKR_OK; } if(builtin->ulValueLen > *len) { *len = builtin->ulValueLen; return CKR_BUFFER_TOO_SMALL; } *len = builtin->ulValueLen; memcpy(data, builtin->pValue, builtin->ulValueLen); return CKR_OK; } builtin++; } return CKR_ATTRIBUTE_TYPE_INVALID; } static void builtin_release(void* data) { /* Nothing to do to free builtin data */ } static const CkCapiObjectDataVtable builtin_objdata_vtable = { builtin_attribute, builtin_attribute, builtin_attribute, builtin_attribute, builtin_release, }; static CK_RV builtin_load_data(CkCapiSession* sess, CkCapiObject* obj, CkCapiObjectData* objdata) { BuiltinObject* bobj = (BuiltinObject*)obj; ASSERT(bobj); ASSERT(objdata); ASSERT(num_builtins > 0); if(bobj->builtin_index > num_builtins) return CKR_OBJECT_HANDLE_INVALID; objdata->data = (void*)all_builtins[bobj->builtin_index]; objdata->data_funcs = builtin_objdata_vtable; return CKR_OK; } static void builtin_object_release(void* data) { BuiltinObject* bobj = (BuiltinObject*)data; ASSERT(bobj); free(bobj); } static const CkCapiObjectVtable builtin_object_vtable = { builtin_load_data, builtin_object_release, }; static CK_RV register_builtin_object(CkCapiSession* sess, CK_ULONG index, CkCapiObject** obj) { BuiltinObject* bobj; CK_RV ret; bobj = calloc(sizeof(BuiltinObject), 1); if(!bobj) return CKR_HOST_MEMORY; bobj->otype = OBJECT_BUILTIN; bobj->builtin_index = index; bobj->obj.id = 0; bobj->obj.obj_funcs = builtin_object_vtable; bobj->obj.unique_key = UNIQUE_KEY_AT(bobj, otype); bobj->obj.unique_len = UNIQUE_KEY_LEN(bobj, otype, builtin_index); ret = ckcapi_object_register(sess, &(bobj->obj)); if(ret != CKR_OK) { free(bobj); return ret; } ASSERT(bobj->obj.id != 0); *obj = &(bobj->obj); return CKR_OK; } CK_RV ckcapi_builtin_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr) { CkCapiObject* obj; CkCapiObjectData objdata; CK_RV ret = CKR_OK; CK_ULONG i; /* First time around count total number */ if(!num_builtins) { while(all_builtins[num_builtins]) ++num_builtins; ASSERT(num_builtins > 0); } /* Match each certificate */ for(i = 0; i < num_builtins; ++i) { objdata.data = (void*)all_builtins[i]; objdata.data_funcs = builtin_objdata_vtable; if(ckcapi_object_data_match(&objdata, match, count)) { ret = register_builtin_object(sess, i, &obj); if(ret != CKR_OK) break; ckcapi_array_append(arr, obj); } } return ret; }