diff options
| author | Szczepan Zalega <szczepan@nitrokey.com> | 2017-12-04 16:29:56 +0100 | 
|---|---|---|
| committer | Szczepan Zalega <szczepan@nitrokey.com> | 2018-02-28 19:23:04 +0100 | 
| commit | 2faa8f6782a2e6294ed8849048a281d12d60da1c (patch) | |
| tree | 0e8947f40697da905278c44338f948ce5fa2b3c7 | |
| parent | d5486ba77235a874245fbee07a75cea89fa59ea2 (diff) | |
| download | libnitrokey-2faa8f6782a2e6294ed8849048a281d12d60da1c.tar.gz libnitrokey-2faa8f6782a2e6294ed8849048a281d12d60da1c.tar.bz2 | |
Initial support for multiple devices with C++ and test
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
| -rw-r--r-- | .idea/vcs.xml | 3 | ||||
| -rw-r--r-- | CMakeLists.txt | 3 | ||||
| -rw-r--r-- | NitrokeyManager.cc | 30 | ||||
| -rw-r--r-- | device.cc | 29 | ||||
| -rw-r--r-- | include/NitrokeyManager.h | 7 | ||||
| -rw-r--r-- | include/device.h | 10 | ||||
| -rw-r--r-- | unittest/test_multiple_devices.cc | 92 | 
7 files changed, 167 insertions, 7 deletions
| diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 486a99a..94a25f7 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,8 +2,5 @@  <project version="4">    <component name="VcsDirectoryMappings">      <mapping directory="$PROJECT_DIR$" vcs="Git" /> -    <mapping directory="$PROJECT_DIR$/hidapi" vcs="Git" /> -    <mapping directory="$PROJECT_DIR$/python_bindings/pybind11" vcs="Git" /> -    <mapping directory="$PROJECT_DIR$/unittest/Catch" vcs="Git" />    </component>  </project>
\ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a4ebb0..3d788cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,6 +191,9 @@ IF (COMPILE_TESTS)      add_executable (test_issues unittest/test_issues.cc)      target_link_libraries (test_issues ${EXTRA_LIBS} nitrokey catch) +    add_executable (test_multiple_devices unittest/test_multiple_devices.cc) +    target_link_libraries (test_multiple_devices ${EXTRA_LIBS} ${LIBNAME} catch) +  ENDIF() diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index d563b26..da5f61a 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -81,6 +81,11 @@ using nitrokey::misc::strcpyT;          set_debug(true);      }      NitrokeyManager::~NitrokeyManager() { +        for (auto d : connected_devices){ +            if (d.second == nullptr) continue; +            d.second->disconnect(); +            connected_devices[d.first] = nullptr; +        }      }      bool NitrokeyManager::set_current_device_speed(int retry_delay, int send_receive_delay){ @@ -98,6 +103,31 @@ using nitrokey::misc::strcpyT;        return true;      } +    std::vector<std::string> NitrokeyManager::list_devices(){ +        auto p = make_shared<Stick20>(); +        return p->enumerate(); // make static +    } + +    bool NitrokeyManager::connect_with_path(std::string path) { +        std::lock_guard<std::mutex> lock(mex_dev_com_manager); + +        if(connected_devices.find(path) != connected_devices.end() +                && connected_devices[path] != nullptr) { +            device = connected_devices[path]; +            return true; +        } + + +        auto p = make_shared<Stick20>(); +        p->set_path(path); + +        if(!p->connect()) return false; + +        connected_devices [path] = p; +        device = p; +        return true; +    } +      bool NitrokeyManager::connect() {          std::lock_guard<std::mutex> lock(mex_dev_com_manager);          vector< shared_ptr<Device> > devices = { make_shared<Stick10>(), make_shared<Stick20>() }; @@ -20,6 +20,7 @@   */  #include <chrono> +#include <iostream>  #include <thread>  #include <cstddef>  #include <stdexcept> @@ -92,12 +93,20 @@ bool Device::_connect() {    LOG(std::string(__FUNCTION__) + std::string(" *IN* "), Loglevel::DEBUG_L2);  //   hid_init(); // done automatically on hid_open -  mp_devhandle = hid_open(m_vid, m_pid, nullptr); +  if (m_path.empty()){ +    mp_devhandle = hid_open(m_vid, m_pid, nullptr); +  } else { +    mp_devhandle = hid_open_path(m_path.c_str()); +  }    const bool success = mp_devhandle != nullptr;    LOG(std::string("Connection success: ") + std::to_string(success), Loglevel::DEBUG_L2);    return success;  } +void Device::set_path(const std::string path){ +  m_path = path; +} +  int Device::send(const void *packet) {    LOG(__FUNCTION__, Loglevel::DEBUG_L2);    std::lock_guard<std::mutex> lock(mex_dev_com); @@ -160,6 +169,24 @@ int Device::recv(void *packet) {    return status;  } +std::vector<std::string> Device::enumerate(){ +  //TODO make static +  auto pInfo = hid_enumerate(m_vid, m_pid); +  auto pInfo_ = pInfo; +  std::vector<std::string> res; +  while (pInfo != nullptr){ +    std::string a (pInfo->path); +    res.push_back(a); +    pInfo = pInfo->next; +  } + +  if (pInfo_ != nullptr){ +    hid_free_enumeration(pInfo_); +  } + +  return res; +} +  bool Device::could_be_enumerated() {    LOG(__FUNCTION__, Loglevel::DEBUG_L2);    std::lock_guard<std::mutex> lock(mex_dev_com); diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index 0db0856..2a79922 100644 --- a/include/NitrokeyManager.h +++ b/include/NitrokeyManager.h @@ -30,6 +30,7 @@  #include "stick20_commands.h"  #include <vector>  #include <memory> +#include <unordered_map>  namespace nitrokey {      using namespace nitrokey::device; @@ -67,6 +68,8 @@ char * strndup(const char* str, size_t maxlen);          bool get_time(uint64_t time = 0);          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<std::string> list_devices(); +        bool connect_with_path (std::string path);          bool connect(const char *device_model);          bool connect();          bool disconnect(); @@ -198,8 +201,10 @@ char * strndup(const char* str, size_t maxlen);          static shared_ptr <NitrokeyManager> _instance;          std::shared_ptr<Device> device; +        std::unordered_map<std::string, shared_ptr<Device> > connected_devices; -      stick10::ReadSlot::ResponsePayload get_OTP_slot_data(const uint8_t slot_number); + +        stick10::ReadSlot::ResponsePayload get_OTP_slot_data(const uint8_t slot_number);        bool is_valid_hotp_slot_number(uint8_t slot_number) const;          bool is_valid_totp_slot_number(uint8_t slot_number) const;          bool is_valid_password_safe_slot_number(uint8_t slot_number) const; diff --git a/include/device.h b/include/device.h index 1bd4773..f6d2380 100644 --- a/include/device.h +++ b/include/device.h @@ -25,6 +25,7 @@  #include "hidapi/hidapi.h"  #include <cstdint>  #include <string> +#include <vector>  #define HID_REPORT_SIZE 65 @@ -105,8 +106,10 @@ public:     * @return true if visible by OS     */    bool could_be_enumerated(); +  std::vector<std::string> enumerate(); -  void show_stats(); + +        void show_stats();  //  ErrorCounters get_stats(){ return m_counters; }    int get_retry_receiving_count() const { return m_retry_receiving_count; };    int get_retry_sending_count() const { return m_retry_sending_count; }; @@ -121,8 +124,10 @@ public:    void set_retry_delay(std::chrono::milliseconds delay);    static void set_default_device_speed(int delay);    void setDefaultDelay(); +  void set_path(const std::string path); + -private: +        private:    std::atomic<uint8_t> last_command_status;    void _reconnect();    bool _connect(); @@ -143,6 +148,7 @@ protected:    std::chrono::milliseconds m_retry_timeout;    std::chrono::milliseconds m_send_receive_delay;    std::atomic<hid_device *>mp_devhandle; +  std::string m_path;    static std::atomic_int instances_count;    static std::chrono::milliseconds default_delay ; diff --git a/unittest/test_multiple_devices.cc b/unittest/test_multiple_devices.cc new file mode 100644 index 0000000..f5b4d6e --- /dev/null +++ b/unittest/test_multiple_devices.cc @@ -0,0 +1,92 @@ + +static const char *const default_admin_pin = "12345678"; +static const char *const default_user_pin = "123456"; +const char * temporary_password = "123456789012345678901234"; +const char * RFC_SECRET = "12345678901234567890"; + +#include "catch.hpp" + +#include <iostream> +#include <NitrokeyManager.h> +#include <iostream> +#include <stick20_commands.h> + +using namespace nitrokey; + + +TEST_CASE("List devices", "[BASIC]") { +    shared_ptr<Stick20> d = make_shared<Stick20>(); +    auto v = d->enumerate(); +    REQUIRE(v.size() > 0); +    for (auto a : v){ +        std::cout << a; +        d->set_path(a); +        d->connect(); +        auto res = GetStatus::CommandTransaction::run(d); +        auto res2 = GetDeviceStatus::CommandTransaction::run(d); +        std::cout << " " << res.data().card_serial_u32 << " " +                  << res.data().get_card_serial_hex() +                  << " " << std::to_string(res2.data().versionInfo.minor) +                  << std::endl; +        d->disconnect(); +    } +} + +TEST_CASE("Regenerate AES keys", "[BASIC]") { +    shared_ptr<Stick20> d = make_shared<Stick20>(); +    auto v = d->enumerate(); +    REQUIRE(v.size() > 0); + +    std::vector<shared_ptr<Stick20>> devices; +    for (auto a : v){ +        std::cout << a << endl; +        d = make_shared<Stick20>(); +        d->set_path(a); +        d->connect(); +        devices.push_back(d); +    } + +    for (auto d : devices){ +        auto res2 = GetDeviceStatus::CommandTransaction::run(d); +        std::cout << std::to_string(res2.data().versionInfo.minor) << std::endl; +//        nitrokey::proto::stick20::CreateNewKeys::CommandPayload p; +//        p.set_defaults(); +//        memcpy(p.password, "12345678", 8); +//        auto res3 = nitrokey::proto::stick20::CreateNewKeys::CommandTransaction::run(d, p); +    } + +    for (auto d : devices){ +        //TODO watch out for multiple hid_exit calls +        d->disconnect(); +    } +} + + +TEST_CASE("Use API", "[BASIC]") { +    auto nm = NitrokeyManager::instance(); +    nm->set_loglevel(2); +    auto v = nm->list_devices(); +    REQUIRE(v.size() > 0); + +    for (int i=0; i<10; i++){ +        for (auto a : v) { +            std::cout <<"Connect with: " << a << +            " " << std::boolalpha << nm->connect_with_path(a) << " "; +            try{ +                auto status_storage = nm->get_status_storage(); +                std::cout << status_storage.ActiveSmartCardID_u32 +                          << " " << status_storage.ActiveSD_CardID_u32 +                          << std::endl; + +                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); +            } +        } +        std::cout <<"Iteration: " << i << std::endl; +    } + +}
\ No newline at end of file | 
