aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSzczepan Zalega <szczepan@nitrokey.com>2017-12-04 16:29:56 +0100
committerSzczepan Zalega <szczepan@nitrokey.com>2018-02-28 19:23:04 +0100
commit2faa8f6782a2e6294ed8849048a281d12d60da1c (patch)
tree0e8947f40697da905278c44338f948ce5fa2b3c7
parentd5486ba77235a874245fbee07a75cea89fa59ea2 (diff)
downloadlibnitrokey-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.xml3
-rw-r--r--CMakeLists.txt3
-rw-r--r--NitrokeyManager.cc30
-rw-r--r--device.cc29
-rw-r--r--include/NitrokeyManager.h7
-rw-r--r--include/device.h10
-rw-r--r--unittest/test_multiple_devices.cc92
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>() };
diff --git a/device.cc b/device.cc
index ac31b1d..5a83e2e 100644
--- a/device.cc
+++ b/device.cc
@@ -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