From 388cf5fcb33f24bc04f79cd1fbea980214518d54 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Mon, 4 Dec 2017 19:21:09 +0100 Subject: List devices by unique SC:SD id Add C API and tests Add mutexes Signed-off-by: Szczepan Zalega --- NK_C_API.cc | 21 ++++++++++ NK_C_API.h | 6 +++ NitrokeyManager.cc | 87 +++++++++++++++++++++++++++++++++++---- include/NitrokeyManager.h | 3 ++ unittest/test_C_API.cpp | 28 +++++++++++++ unittest/test_multiple_devices.cc | 24 ++++++++++- 6 files changed, 160 insertions(+), 9 deletions(-) diff --git a/NK_C_API.cc b/NK_C_API.cc index f881caf..59247ba 100644 --- a/NK_C_API.cc +++ b/NK_C_API.cc @@ -608,6 +608,27 @@ extern "C" { }); } + NK_C_API const char* NK_list_devices_by_cpuID() { + auto nm = NitrokeyManager::instance(); + return get_with_string_result([&]() { + auto v = nm->list_devices_by_cpuID(); + std::string res; + for (const auto a : v){ + res += a+";"; + } + if (res.size()>0) res.pop_back(); // remove last delimeter char + return strndup(res.c_str(), 4096); + }); + } + + NK_C_API int NK_connect_with_ID(const char* id) { + auto m = NitrokeyManager::instance(); + return get_with_result([&]() { + return m->connect_with_ID(id) ? 1 : 0; + }); + } + + #ifdef __cplusplus } diff --git a/NK_C_API.h b/NK_C_API.h index 73022b2..5933c67 100644 --- a/NK_C_API.h +++ b/NK_C_API.h @@ -568,6 +568,12 @@ extern "C" { */ NK_C_API int NK_get_progress_bar_value(); + + NK_C_API const char* NK_list_devices_by_cpuID(); + NK_C_API int NK_connect_with_ID(const char* id); + + + #ifdef __cplusplus } #endif diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index da5f61a..4935076 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -81,6 +81,8 @@ using nitrokey::misc::strcpyT; set_debug(true); } NitrokeyManager::~NitrokeyManager() { + std::lock_guard lock(mex_dev_com_manager); + for (auto d : connected_devices){ if (d.second == nullptr) continue; d.second->disconnect(); @@ -104,27 +106,98 @@ using nitrokey::misc::strcpyT; } std::vector NitrokeyManager::list_devices(){ + std::lock_guard lock(mex_dev_com_manager); + auto p = make_shared(); return p->enumerate(); // make static } - bool NitrokeyManager::connect_with_path(std::string path) { + std::vector NitrokeyManager::list_devices_by_cpuID(){ std::lock_guard lock(mex_dev_com_manager); - if(connected_devices.find(path) != connected_devices.end() - && connected_devices[path] != nullptr) { - device = connected_devices[path]; - return true; + std::vector res; + auto d = make_shared(); + const auto v = d->enumerate(); + for (auto & p: v){ + d = make_shared(); + d->set_path(p); + try{ + if (d->connect()){ + device = d; + const auto status = get_status_storage(); + const auto sc_id = status.ActiveSmartCardID_u32; + const auto sd_id = status.ActiveSD_CardID_u32; + + auto id = std::to_string(sc_id) + ":" + std::to_string(sd_id); + connected_devices_byID[id] = d; + res.push_back(id); + } else{ + std::cout << "Could not connect to: " + p << std::endl; + } + } + catch (const DeviceCommunicationException &e){ + //ignore + std::cout << p << ": " << " Exception encountered" << std::endl; + } } + return res; + } +/** + * Connect to the device using unique smartcard:datacard id. + * Needs list_device_by_cpuID run first + * @param id + * @return + */ + bool NitrokeyManager::connect_with_ID(const std::string id) { + std::lock_guard lock(mex_dev_com_manager); + auto position = connected_devices_byID.find(id); + if (position == connected_devices_byID.end()) return false; + + auto d = connected_devices_byID[id]; + device = d; + + try{ + get_status(); + } + catch (const DeviceCommunicationException &){ + d->disconnect(); + connected_devices_byID[id] = nullptr; + connected_devices_byID.erase(position); + return false; + } + return true; + } + + /** + * Connects device to path. + * Assumes devices are not being disconnected and caches connections (param cache_connections). + * @param path os-dependent device path + * @return false, when could not connect, true otherwise + */ + bool NitrokeyManager::connect_with_path(std::string path) { + const bool cache_connections = false; + + std::lock_guard lock(mex_dev_com_manager); + + if (cache_connections){ + if(connected_devices.find(path) != connected_devices.end() + && connected_devices[path] != nullptr) { + device = connected_devices[path]; + return true; + } + } auto p = make_shared(); p->set_path(path); if(!p->connect()) return false; - connected_devices [path] = p; - device = p; + if(cache_connections){ + connected_devices [path] = p; + } + + device = p; //previous device will be disconnected automatically return true; } diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index 2a79922..7ce432f 100644 --- a/include/NitrokeyManager.h +++ b/include/NitrokeyManager.h @@ -69,6 +69,8 @@ char * strndup(const char* str, size_t maxlen); bool erase_totp_slot(uint8_t slot_number, const char *temporary_password); bool erase_hotp_slot(uint8_t slot_number, const char *temporary_password); std::vector list_devices(); + std::vector list_devices_by_cpuID(); + bool connect_with_ID(const std::string id); bool connect_with_path (std::string path); bool connect(const char *device_model); bool connect(); @@ -202,6 +204,7 @@ char * strndup(const char* str, size_t maxlen); static shared_ptr _instance; std::shared_ptr device; std::unordered_map > connected_devices; + std::unordered_map > connected_devices_byID; stick10::ReadSlot::ResponsePayload get_OTP_slot_data(const uint8_t slot_number); diff --git a/unittest/test_C_API.cpp b/unittest/test_C_API.cpp index be47f08..2d83ef4 100644 --- a/unittest/test_C_API.cpp +++ b/unittest/test_C_API.cpp @@ -43,6 +43,7 @@ TEST_CASE("C API connect", "[BASIC]") { TEST_CASE("Check retry count", "[BASIC]") { REQUIRE(login != 0); + NK_set_debug_level(3); REQUIRE(NK_get_admin_retry_count() == 3); REQUIRE(NK_get_user_retry_count() == 3); } @@ -56,4 +57,31 @@ TEST_CASE("Check long strings", "[STANDARD]") { result = NK_change_user_PIN(pin, longPin); REQUIRE(result == TOO_LONG_STRING); CAPTURE(result); +} + +#include + +TEST_CASE("multiple devices with ID", "[BASIC]") { + NK_logout(); + NK_set_debug_level(3); + auto s = NK_list_devices_by_cpuID(); + REQUIRE(s!=nullptr); + REQUIRE(strnlen(s, 4096) < 4096); + REQUIRE(strnlen(s, 4096) > 2*4); + std::cout << s << std::endl; + + char *string, *token; + int t; + + string = strndup(s, 4096); + free ( (void*) s); + + while ((token = strsep(&string, ";")) != nullptr){ + if (strnlen(token, 4096) < 3) continue; + std::cout << token << " connecting: "; + std::cout << (t=NK_connect_with_ID(token)) << std::endl; + REQUIRE(t == 1); + } + + free (string); } \ No newline at end of file diff --git a/unittest/test_multiple_devices.cc b/unittest/test_multiple_devices.cc index f5b4d6e..235a24d 100644 --- a/unittest/test_multiple_devices.cc +++ b/unittest/test_multiple_devices.cc @@ -78,15 +78,35 @@ TEST_CASE("Use API", "[BASIC]") { << " " << status_storage.ActiveSD_CardID_u32 << std::endl; - nm->fill_SD_card_with_random_data("12345678"); +// nm->fill_SD_card_with_random_data("12345678"); } catch (const LongOperationInProgressException &e){ std::cout << "long operation in progress on " << a << " " << std::to_string(e.progress_bar_value) << std::endl; - this_thread::sleep_for(1000ms); +// this_thread::sleep_for(1000ms); } } std::cout <<"Iteration: " << i << std::endl; } +} + + +TEST_CASE("Use API ID", "[BASIC]") { + auto nm = NitrokeyManager::instance(); + nm->set_loglevel(2); + + auto v = nm->list_devices_by_cpuID(); + REQUIRE(v.size() > 0); + + for(int i=0; i<1000; i++) { + auto v = nm->list_devices_by_cpuID(); + REQUIRE(v.size() > 0); + for (auto i : v) { + nm->connect_with_ID(i); + auto retry_count = nm->get_admin_retry_count(); + std::cout << i << " " << to_string(retry_count) << std::endl; + } + } + std::cout << "finished" << std::endl; } \ No newline at end of file -- cgit v1.2.3