From 82eee65daf1f57988a41ae2409506b02f6b6225a Mon Sep 17 00:00:00 2001 From: David Fort Date: Sun, 16 Jan 2022 22:28:51 +0100 Subject: [PATCH] winpr: fix ncrypt on Mac and updated tests --- winpr/libwinpr/ncrypt/CMakeLists.txt | 5 + winpr/libwinpr/ncrypt/ncrypt.c | 25 ++- winpr/libwinpr/ncrypt/ncrypt_pkcs11.c | 15 +- winpr/libwinpr/ncrypt/test/CMakeLists.txt | 2 +- .../ncrypt/test/TestNCryptSmartcard.c | 143 +++++++++++++----- 5 files changed, 146 insertions(+), 44 deletions(-) diff --git a/winpr/libwinpr/ncrypt/CMakeLists.txt b/winpr/libwinpr/ncrypt/CMakeLists.txt index c41a3fd9b..4487fb211 100644 --- a/winpr/libwinpr/ncrypt/CMakeLists.txt +++ b/winpr/libwinpr/ncrypt/CMakeLists.txt @@ -21,6 +21,11 @@ winpr_module_add( ncrypt_pkcs11.c ) +if(WITH_PKCS11 AND NOT WIN32) + winpr_include_directory_add(${PKCS11_INCLUDE_DIR}) + winpr_library_add_public(${PKCS11_LIBRARY}) +endif() + if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/ncrypt/ncrypt.c b/winpr/libwinpr/ncrypt/ncrypt.c index d5d4d5027..d3b52360e 100644 --- a/winpr/libwinpr/ncrypt/ncrypt.c +++ b/winpr/libwinpr/ncrypt/ncrypt.c @@ -121,15 +121,35 @@ SECURITY_STATUS NCryptEnumStorageProviders(DWORD* wProviderCount, return ERROR_SUCCESS; } + SECURITY_STATUS NCryptOpenStorageProvider(NCRYPT_PROV_HANDLE* phProvider, LPCWSTR pszProviderName, DWORD dwFlags) { #ifdef WITH_PKCS11 + +#if defined(__LP64__) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +# define LIBS64 +#endif + if (_wcscmp(pszProviderName, MS_SMART_CARD_KEY_STORAGE_PROVIDER) == 0 || _wcscmp(pszProviderName, MS_SCARD_PROV) == 0) { - static LPCSTR openscPaths[] = { "/usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so", NULL }; + static LPCSTR openscPaths[] = { +#ifdef __APPLE__ + "/usr/local/lib/pkcs11/opensc-pkcs11.so", +#else + /* linux and UNIXes */ +#ifdef LIBS64 + "/usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so", /* Ubuntu/debian */ + "/lib64/pkcs11/opensc-pkcs11.so", /* Fedora */ +#else + "/usr/lib/i386-linux-gnu/opensc-pkcs11.so", /* debian */ + "/lib32/pkcs11/opensc-pkcs11.so", /* Fedora */ +#endif +#endif + NULL + }; return winpr_NCryptOpenStorageProviderEx(phProvider, pszProviderName, dwFlags, openscPaths); } @@ -149,6 +169,9 @@ SECURITY_STATUS winpr_NCryptOpenStorageProviderEx(NCRYPT_PROV_HANDLE* phProvider SECURITY_STATUS NCryptOpenP11StorageProviderEx(NCRYPT_PROV_HANDLE * phProvider, LPCWSTR pszProviderName, DWORD dwFlags, LPCSTR * modulePaths); + + if (!modulePaths) + return ERROR_INVALID_PARAMETER; return NCryptOpenP11StorageProviderEx(phProvider, pszProviderName, dwFlags, modulePaths); } #endif diff --git a/winpr/libwinpr/ncrypt/ncrypt_pkcs11.c b/winpr/libwinpr/ncrypt/ncrypt_pkcs11.c index 0026deaca..a840e1dd5 100644 --- a/winpr/libwinpr/ncrypt/ncrypt_pkcs11.c +++ b/winpr/libwinpr/ncrypt/ncrypt_pkcs11.c @@ -399,7 +399,7 @@ static SECURITY_STATUS parseKeyName(LPCWSTR pszKeyName, CK_SLOT_ID* slotId, CK_B char* pos; if (WideCharToMultiByte(CP_UTF8, 0, pszKeyName, _wcslen(pszKeyName) + 1, asciiKeyName, - sizeof(asciiKeyName), "?", FALSE) <= 0) + sizeof(asciiKeyName)-1, "?", FALSE) <= 0) return NTE_BAD_KEY; if (*asciiKeyName != '\\') @@ -625,14 +625,16 @@ static SECURITY_STATUS NCryptP11KeyGetProperties(NCryptP11KeyHandle* keyHandle, if (rv != CKR_OK) return NTE_BAD_KEY; - fix_padded_string((char*)slotInfo.slotDescription, sizeof(slotInfo.slotDescription)); - *pcbResult = 2 * (strlen((char*)slotInfo.slotDescription) + 1); + #define SLOT_DESC_SZ sizeof(slotInfo.slotDescription) + fix_padded_string((char*)slotInfo.slotDescription, SLOT_DESC_SZ); + *pcbResult = 2 * (strnlen((char*)slotInfo.slotDescription, SLOT_DESC_SZ) + 1); if (pbOutput) { if(cbOutput < *pcbResult) return NTE_NO_MEMORY; - MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)slotInfo.slotDescription, -1, (LPWSTR)pbOutput, cbOutput); + if (MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)slotInfo.slotDescription, -1, (LPWSTR)pbOutput, cbOutput) <= 0) + return NTE_NO_MEMORY; } return ERROR_SUCCESS; } @@ -772,11 +774,12 @@ SECURITY_STATUS NCryptOpenP11StorageProviderEx(NCRYPT_PROV_HANDLE* phProvider, while (*modulePaths) { + WLog_DBG(TAG, "Trying pkcs11-helper module '%s'", *modulePaths); ret->library = LoadLibrary(*modulePaths); if (!ret->library) { status = NTE_PROV_DLL_NOT_FOUND; - continue; + goto out_load_library; } c_get_function_list = GetProcAddress(ret->library, "C_GetFunctionList"); @@ -800,11 +803,13 @@ SECURITY_STATUS NCryptOpenP11StorageProviderEx(NCRYPT_PROV_HANDLE* phProvider, goto out_lib_entry; } + WLog_DBG(TAG, "module '%s' loaded", *modulePaths); *phProvider = (NCRYPT_PROV_HANDLE)ret; return ERROR_SUCCESS; out_lib_entry: FreeLibrary(ret->library); + out_load_library: modulePaths++; } diff --git a/winpr/libwinpr/ncrypt/test/CMakeLists.txt b/winpr/libwinpr/ncrypt/test/CMakeLists.txt index b34ac4e54..fbad47af6 100644 --- a/winpr/libwinpr/ncrypt/test/CMakeLists.txt +++ b/winpr/libwinpr/ncrypt/test/CMakeLists.txt @@ -21,7 +21,7 @@ foreach(test ${${MODULE_PREFIX}_TESTS}) add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName}) endforeach() -target_link_libraries(${MODULE_NAME} winpr) +target_link_libraries(${MODULE_NAME} winpr ${OPENSSL_LIBRARIES}) if(WIN32) target_link_libraries(${MODULE_NAME} ncrypt) endif() diff --git a/winpr/libwinpr/ncrypt/test/TestNCryptSmartcard.c b/winpr/libwinpr/ncrypt/test/TestNCryptSmartcard.c index 4863efa9c..1620bce11 100644 --- a/winpr/libwinpr/ncrypt/test/TestNCryptSmartcard.c +++ b/winpr/libwinpr/ncrypt/test/TestNCryptSmartcard.c @@ -22,60 +22,129 @@ #include #include +#include +#include + #define TAG "testNCrypt" +static void crypto_print_name(const BYTE *b, DWORD sz) +{ + X509_NAME* name; + X509* x509; + BIO* bio; + char *ret; + + bio = BIO_new_mem_buf(b, sz); + if (!bio) + return; + + x509 = d2i_X509_bio(bio, NULL); + if (!x509) + goto bio_release; + + name = X509_get_subject_name(x509); + if (!name) + goto x509_release; + + ret = malloc(1024); + if (!ret) + goto bio_release; + + ret = X509_NAME_oneline(name, ret, 1024); + + printf("\t%s\n", ret); + free(ret); + +x509_release: + X509_free(x509); +bio_release: + BIO_free(bio); +} + int TestNCryptSmartcard(int argc, char* argv[]) { SECURITY_STATUS status; - NCRYPT_PROV_HANDLE provider; - PVOID enumState = NULL; - NCryptKeyName* keyName = NULL; + size_t j = 0; + DWORD providerCount; + NCryptProviderName *names; - status = NCryptOpenStorageProvider(&provider, MS_SMART_CARD_KEY_STORAGE_PROVIDER, 0); + status = NCryptEnumStorageProviders(&providerCount, &names, NCRYPT_SILENT_FLAG); if (status != ERROR_SUCCESS) - return 0; + return -1; - while ((status = NCryptEnumKeys(provider, NULL, &keyName, &enumState, NCRYPT_SILENT_FLAG)) == - ERROR_SUCCESS) + for (j = 0; j < providerCount; j++) { - NCRYPT_KEY_HANDLE phKey; - DWORD dwFlags = 0, cbOutput; - char keyNameStr[256]; - PBYTE certBytes = NULL; + NCRYPT_PROV_HANDLE provider; + char providerNameStr[256] = { 0 }; + PVOID enumState = NULL; + size_t i = 0; + NCryptKeyName* keyName = NULL; - WideCharToMultiByte(CP_UTF8, 0, keyName->pszName, -1, keyNameStr, sizeof(keyNameStr), NULL, - FALSE); - - status = - NCryptOpenKey(provider, &phKey, keyName->pszName, keyName->dwLegacyKeySpec, dwFlags); - if (status != ERROR_SUCCESS) - { - WLog_ERR(TAG, "unable to open key %s", keyNameStr); + if (WideCharToMultiByte(CP_UTF8, 0, names[j].pszName, -1, providerNameStr, sizeof(providerNameStr), NULL, + FALSE) <= 0) continue; - } + printf("provider %ld: %s\n", j, providerNameStr); - status = NCryptGetProperty(phKey, NCRYPT_CERTIFICATE_PROPERTY, NULL, 0, &cbOutput, dwFlags); + status = NCryptOpenStorageProvider(&provider, names[j].pszName, 0); if (status != ERROR_SUCCESS) + continue; + + while ((status = NCryptEnumKeys(provider, NULL, &keyName, &enumState, NCRYPT_SILENT_FLAG)) == + ERROR_SUCCESS) { - WLog_ERR(TAG, "unable to retrieve certificate for key %s", keyNameStr); + NCRYPT_KEY_HANDLE phKey; + DWORD dwFlags = 0, cbOutput; + char keyNameStr[256] = { 0 }; + WCHAR reader[1024] = { 0 }; + PBYTE certBytes = NULL; + + if (WideCharToMultiByte(CP_UTF8, 0, keyName->pszName, -1, keyNameStr, sizeof(keyNameStr), NULL, + FALSE) <= 0) + continue; + + printf("\tkey %ld: %s\n", i, keyNameStr); + status = + NCryptOpenKey(provider, &phKey, keyName->pszName, keyName->dwLegacyKeySpec, dwFlags); + if (status != ERROR_SUCCESS) + { + WLog_ERR(TAG, "unable to open key %s", keyNameStr); + continue; + } + + status = NCryptGetProperty(phKey, NCRYPT_READER_PROPERTY, (PBYTE)reader, sizeof(reader), &cbOutput, dwFlags); + if (status == ERROR_SUCCESS) + { + char readerStr[1024] = { 0 }; + if (WideCharToMultiByte(CP_UTF8, 0, reader, cbOutput, readerStr, sizeof(readerStr), NULL, FALSE) > 0) + printf("\treader: %s\n", readerStr); + } + + status = NCryptGetProperty(phKey, NCRYPT_CERTIFICATE_PROPERTY, NULL, 0, &cbOutput, dwFlags); + if (status != ERROR_SUCCESS) + { + /* WLog_ERR(TAG, "unable to retrieve certificate for key '%s'", keyNameStr); */ + goto endofloop; + } + + certBytes = calloc(1, cbOutput); + status = NCryptGetProperty(phKey, NCRYPT_CERTIFICATE_PROPERTY, certBytes, cbOutput, + &cbOutput, dwFlags); + if (status != ERROR_SUCCESS) + { + WLog_ERR(TAG, "unable to retrieve certificate for key %s", keyNameStr); + goto endofloop; + } + + crypto_print_name(certBytes, cbOutput); + free(certBytes); + + endofloop: NCryptFreeObject((NCRYPT_HANDLE)phKey); - continue; + i++; } - certBytes = calloc(1, cbOutput); - status = NCryptGetProperty(phKey, NCRYPT_CERTIFICATE_PROPERTY, certBytes, cbOutput, - &cbOutput, dwFlags); - if (status != ERROR_SUCCESS) - { - WLog_ERR(TAG, "unable to retrieve certificate for key %s", keyNameStr); - NCryptFreeObject((NCRYPT_HANDLE)phKey); - continue; - } - - NCryptFreeObject((NCRYPT_HANDLE)phKey); + NCryptFreeObject((NCRYPT_HANDLE)enumState); + NCryptFreeObject((NCRYPT_HANDLE)provider); } - - NCryptFreeObject((NCRYPT_HANDLE)enumState); - NCryptFreeObject((NCRYPT_HANDLE)provider); return 0; }