From 0ba89ba85a58264e4b1b44a5593e84fb070126e3 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Sat, 28 Apr 2007 04:35:20 +0000 Subject: Show windows CAPI certificates. Basic implementation and functionality complete. --- ckcapi-cert.c | 90 +++++++++++++++++++++++++++++++++++++-------------------- ckcapi-object.c | 73 ++++++++++++++++++++++++++++++++++++---------- ckcapi-util.c | 3 +- ckcapi.c | 3 ++ ckcapi.dsp | 6 ++-- ckcapi.h | 2 ++ 6 files changed, 127 insertions(+), 50 deletions(-) diff --git a/ckcapi-cert.c b/ckcapi-cert.c index 7436307..0605ef9 100644 --- a/ckcapi-cert.c +++ b/ckcapi-cert.c @@ -5,6 +5,14 @@ #include +#ifndef CERT_FIND_KEY_IDENTIFIER +#define CERT_FIND_KEY_IDENTIFIER 983040 +#endif + +#ifndef CERT_KEY_IDENTIFIER_PROP_ID +#define CERT_KEY_IDENTIFIER_PROP_ID 20 +#endif + typedef struct _CertObject { CkCapiObject obj; @@ -145,7 +153,8 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type, CK_VOID_PTR data, CK_ULONG_PTR len) { PCCERT_CONTEXT cert = (PCCERT_CONTEXT)obj; - + DWORD err; + ASSERT(sizeof(CK_ULONG) == sizeof(DWORD)); ASSERT(obj); @@ -161,27 +170,49 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type, */ case CKA_LABEL: { - WCHAR* utf16; + WCHAR* utf16 = NULL; + DWORD size; /* Get the UTF16 string, a worst case of twice as long as UTF8 */ - (*len) *= sizeof(WCHAR); - utf16 = _alloca(*len); + if(data) + { + size = *len * sizeof(WCHAR); + utf16 = _alloca(size); + } + if(!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, - utf16, (DWORD*)len)) + utf16, &size)) { - DWORD err = GetLastError(); + err = GetLastError(); if(err == CRYPT_E_NOT_FOUND) - utf16 = L"Unnamed Certificate"; + utf16 = L""; else return ckcapi_winerr_to_ckr(err); } - /* Convert the data into the buffer */ - if(!WideCharToMultiByte(CP_UTF8, 0, utf16, -1, data, *len, "?", NULL)) - return ckcapi_winerr_to_ckr(GetLastError()); - return CKR_OK; + if(utf16) + { + /* Always have a default name */ + if(!utf16[0]) + { + utf16 = L"Unnamed Certificate"; + size = wcslen(utf16) * 2; + } + + /* Convert the data into the buffer */ + *len = WideCharToMultiByte(CP_UTF8, 0, utf16, size / sizeof(WCHAR), + data, *len, NULL, NULL); + if(!*len) + return ckcapi_winerr_to_ckr(GetLastError()); + } + else + { + /* Just return an appropriate allocation length */ + *len = (size / sizeof(WCHAR)) + sizeof(WCHAR); + } + } - break; + return CKR_OK; /* * A byte array unique to this certificate. The CKA_ID of @@ -191,17 +222,16 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type, * We use CAPI's CERT_KEY_IDENTIFIER_PROP_ID property directly. */ case CKA_ID: - { - if(!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, + if(!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, data, (DWORD*)len)) - { - DWORD err = GetLastError(); - if(err == CRYPT_E_NOT_FOUND) - return CKR_ATTRIBUTE_TYPE_INVALID; - return ckcapi_winerr_to_ckr(err); - } + { + err = GetLastError(); + if(err == CRYPT_E_NOT_FOUND) + return CKR_ATTRIBUTE_TYPE_INVALID; + return ckcapi_winerr_to_ckr(err); } - break; + return CKR_OK; + /* * DER-encoding of the certificate subject name. @@ -234,17 +264,15 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type, * &size); */ case CKA_SERIAL_NUMBER: + if(!CryptEncodeObject(X509_ASN_ENCODING, X509_MULTI_BYTE_INTEGER, + &cert->pCertInfo->SerialNumber, data, len)) { - if(!CryptEncodeObject(X509_ASN_ENCODING, X509_MULTI_BYTE_INTEGER, - &cert->pCertInfo->SerialNumber, data, len)) - { - DWORD err = GetLastError(); - if(err == ERROR_FILE_NOT_FOUND) - return CKR_GENERAL_ERROR; - return ckcapi_winerr_to_ckr(err); - } + err = GetLastError(); + if(err == ERROR_FILE_NOT_FOUND) + return CKR_GENERAL_ERROR; + return ckcapi_winerr_to_ckr(err); } - break; + return CKR_OK; /* * BER-encoding of the full certificate. @@ -469,7 +497,7 @@ ckcapi_cert_find_in_store(CkCapiSession* sess, const char* store_name, if(ckcapi_object_data_match(&objdata, match, count)) { - ret = register_cert_object(sess, store, cert, &obj); + ret = register_cert_object(sess, store_name, cert, &obj); if(ret != CKR_OK) break; diff --git a/ckcapi-object.c b/ckcapi-object.c index c02c365..c620cc4 100644 --- a/ckcapi-object.c +++ b/ckcapi-object.c @@ -17,6 +17,34 @@ object_free(CkCapiObject* obj) (obj->obj_funcs.release)(obj); } +void +ckcapi_object_clear_all(void) +{ + size_t i; + + ckcapi_lock_global(); + + if(object_hash) + { + ckcapi_hash_free(object_hash); + object_hash = NULL; + } + + if(object_array) + { + for(i = 0; i < object_array->len; ++i) + { + ASSERT(ckcapi_array_index(object_array, CkCapiObject*, i)); + object_free(ckcapi_array_index(object_array, CkCapiObject*, i)); + } + + ckcapi_array_free(object_array, TRUE); + object_array = NULL; + } + + ckcapi_unlock_global(); +} + CkCapiObject* ckcapi_object_lookup(CkCapiSession* sess, CK_OBJECT_HANDLE obj) { @@ -48,7 +76,7 @@ ckcapi_object_register(CkCapiSession* sess, CkCapiObject* obj) ASSERT(obj->unique_key); ASSERT(obj->unique_len); - DBGS(sess, "registering new session"); + DBGS(sess, "registering new object"); ckcapi_lock_global(); @@ -364,7 +392,7 @@ ckcapi_object_data_get_attrs(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attrs, break; case DATA_ULONG: rv = (objdata->data_funcs.get_ulong)(objdata->data, attrs[i].type, - attrs[i].pValue, &attrs[i].ulValueLen); + attrs[i].pValue, &attrs[i].ulValueLen); break; case DATA_BYTES: rv = (objdata->data_funcs.get_bytes)(objdata->data, attrs[i].type, @@ -383,23 +411,36 @@ ckcapi_object_data_get_attrs(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attrs, }; /* Not an error if they were just requesting the size */ - if(rv == CKR_BUFFER_TOO_SMALL) + if(rv != CKR_OK) { - if(!attrs[i].pValue) - rv = CKR_OK; - } + if(rv == CKR_BUFFER_TOO_SMALL) + { + if(!attrs[i].pValue) + rv = CKR_OK; + } - /* Is it a fatal error? */ - else if(rv != CKR_ATTRIBUTE_TYPE_INVALID) - { - ret = rv; - break; - } + /* Attribute is sensitive */ + else if(rv == CKR_ATTRIBUTE_SENSITIVE) + { + attrs[i].ulValueLen = (CK_ULONG)-1; + } - /* Transfer any non-fatal errors outward */ - if(rv != CKR_OK && ret == CKR_OK) - { - ret = rv; + /* Attribute doesn't exist */ + else if(rv == CKR_ATTRIBUTE_TYPE_INVALID) + { + attrs[i].ulValueLen = (CK_ULONG)-1; + } + + /* A fatal error? */ + else + { + ret = rv; + break; + } + + /* Transfer any non-fatal errors outward */ + if(rv != CKR_OK && ret == CKR_OK) + ret = rv; } } diff --git a/ckcapi-util.c b/ckcapi-util.c index 6969c2e..4078ab5 100644 --- a/ckcapi-util.c +++ b/ckcapi-util.c @@ -99,7 +99,8 @@ ckcapi_array_free(CkCapiArray* array, int free_segment) if(free_segment) { - free(array->data); + if(array->data) + free(array->data); segment = NULL; } else diff --git a/ckcapi.c b/ckcapi.c index 971b034..84538c8 100644 --- a/ckcapi.c +++ b/ckcapi.c @@ -161,6 +161,9 @@ CC_C_Finalize(CK_VOID_PTR pReserved) cryptoki_initialized = 0; + ckcapi_session_close_all(); + ckcapi_object_clear_all(); + RETURN(CKR_OK); } diff --git a/ckcapi.dsp b/ckcapi.dsp index a5b73e8..c50d0af 100644 --- a/ckcapi.dsp +++ b/ckcapi.dsp @@ -40,6 +40,7 @@ RSC=rc.exe # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /c # ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /c @@ -52,7 +53,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib crypt32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "cryptoki_capi - Win32 Debug" @@ -65,6 +66,7 @@ LINK32=link.exe # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CRYPTOKI_CAPI_EXPORTS" /YX /FD /GZ /c @@ -77,7 +79,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib crypt32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF diff --git a/ckcapi.h b/ckcapi.h index 6442a8d..2f832dd 100644 --- a/ckcapi.h +++ b/ckcapi.h @@ -129,6 +129,8 @@ CkCapiObject* ckcapi_object_lookup (CkCapiSession* sess, CK_OBJECT_HANDLE obj CK_RV ckcapi_object_register (CkCapiSession* sess, CkCapiObject* obj); +void ckcapi_object_clear_all (void); + CK_RV ckcapi_object_load_data (CkCapiObject* obj, CkCapiObjectData* objdata); CK_RV ckcapi_object_load_data_for (CkCapiSession* sess, CK_OBJECT_HANDLE hand, -- cgit v1.2.3