1 /* 2 * Copyright (c) 2015-2018 Nitrokey UG 3 * 4 * This file is part of libnitrokey. 5 * 6 * libnitrokey is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * any later version. 10 * 11 * libnitrokey is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>. 18 * 19 * SPDX-License-Identifier: LGPL-3.0 20 */ 21 22 #ifndef DEVICE_H 23 #define DEVICE_H 24 #include <chrono> 25 #include "hidapi/hidapi.h" 26 #include <cstdint> 27 #include <memory> 28 #include <string> 29 #include <ostream> 30 #include <vector> 31 #include "misc.h" 32 33 #define HID_REPORT_SIZE 65 34 35 #include <atomic> 36 37 namespace nitrokey { 38 namespace device { 39 using namespace std::chrono_literals; 40 using std::chrono::milliseconds; 41 42 struct EnumClassHash 43 { 44 template <typename T> operatorEnumClassHash45 std::size_t operator()(T t) const 46 { 47 return static_cast<std::size_t>(t); 48 } 49 }; 50 51 enum class DeviceModel{ 52 PRO, 53 STORAGE, 54 LIBREM 55 }; 56 57 std::ostream& operator<<(std::ostream& stream, DeviceModel model); 58 59 /** 60 * The USB vendor ID for Nitrokey devices. 61 */ 62 extern const uint16_t NITROKEY_VID; 63 /** 64 * The USB product ID for the Nitrokey Pro. 65 */ 66 extern const uint16_t NITROKEY_PRO_PID; 67 /** 68 * The USB product ID for the Nitrokey Storage. 69 */ 70 extern const uint16_t NITROKEY_STORAGE_PID; 71 /** 72 * The USB vendor ID for Purism devices. 73 */ 74 extern const uint16_t PURISM_VID; 75 /** 76 * The USB product ID for the Librem Key. 77 */ 78 extern const uint16_t LIBREM_KEY_PID; 79 80 /** 81 * Convert the given USB product ID to a Nitrokey model. If there is no model 82 * with that ID, return an absent value. 83 */ 84 misc::Option<DeviceModel> product_id_to_model(uint16_t product_id); 85 misc::Option<DeviceModel> product_id_to_model(uint16_t vendor_id, uint16_t product_id); 86 87 /** 88 * Information about a connected device. 89 * 90 * This struct contains the information about a connected device returned by 91 * hidapi when enumerating the connected devices. 92 */ 93 struct DeviceInfo { 94 /** 95 * The model of the connected device. 96 */ 97 DeviceModel m_deviceModel; 98 /** 99 * The USB connection path for the device. 100 */ 101 std::string m_path; 102 /** 103 * The serial number of the device. 104 */ 105 std::string m_serialNumber; 106 }; 107 108 #include <atomic> 109 110 class Device { 111 112 public: 113 114 struct ErrorCounters{ 115 using cnt = std::atomic_int; 116 cnt wrong_CRC; 117 cnt CRC_other_than_awaited; 118 cnt busy; 119 cnt total_retries; 120 cnt sending_error; 121 cnt receiving_error; 122 cnt total_comm_runs; 123 cnt successful_storage_commands; 124 cnt command_successful_recv; 125 cnt recv_executed; 126 cnt sends_executed; 127 cnt busy_progressbar; 128 cnt command_result_not_equal_0_recv; 129 cnt communication_successful; 130 cnt low_level_reconnect; 131 std::string get_as_string(); 132 133 } m_counters = {}; 134 135 136 Device(const uint16_t vid, const uint16_t pid, const DeviceModel model, 137 const milliseconds send_receive_delay, const int retry_receiving_count, 138 const milliseconds retry_timeout); 139 140 virtual ~Device(); 141 142 // lack of device is not actually an error, 143 // so it doesn't throw 144 virtual bool connect(); 145 virtual bool disconnect(); 146 147 /* 148 * Sends packet of HID_REPORT_SIZE. 149 */ 150 virtual int send(const void *packet); 151 152 /* 153 * Gets packet of HID_REPORT_SIZE. 154 * Can sleep. See below. 155 */ 156 virtual int recv(void *packet); 157 158 /*** 159 * Returns true if some device is visible by OS with given VID and PID 160 * whether the device is connected through HID API or not. 161 * @return true if visible by OS 162 */ 163 bool could_be_enumerated(); 164 /** 165 * Returns a vector with all connected Nitrokey devices. 166 * 167 * @return information about all connected devices 168 */ 169 static std::vector<DeviceInfo> enumerate(); 170 171 /** 172 * Create a Device of the given model. 173 */ 174 static std::shared_ptr<Device> create(DeviceModel model); 175 176 177 void show_stats(); 178 // ErrorCounters get_stats(){ return m_counters; } get_retry_receiving_count()179 int get_retry_receiving_count() const { return m_retry_receiving_count; }; get_retry_sending_count()180 int get_retry_sending_count() const { return m_retry_sending_count; }; get_retry_timeout()181 std::chrono::milliseconds get_retry_timeout() const { return m_retry_timeout; }; get_send_receive_delay()182 std::chrono::milliseconds get_send_receive_delay() const {return m_send_receive_delay;} 183 get_last_command_status()184 int get_last_command_status() {int a = std::atomic_exchange(&last_command_status, static_cast<uint8_t>(0)); return a;}; set_last_command_status(uint8_t _err)185 void set_last_command_status(uint8_t _err) { last_command_status = _err;} ; last_command_sucessfull()186 bool last_command_sucessfull() const {return last_command_status == 0;}; get_device_model()187 DeviceModel get_device_model() const {return m_model;} 188 void set_receiving_delay(std::chrono::milliseconds delay); 189 void set_retry_delay(std::chrono::milliseconds delay); 190 static void set_default_device_speed(int delay); 191 void setDefaultDelay(); 192 void set_path(const std::string path); 193 194 195 private: 196 std::atomic<uint8_t> last_command_status; 197 void _reconnect(); 198 bool _connect(); 199 bool _disconnect(); 200 201 protected: 202 const uint16_t m_vid; 203 const uint16_t m_pid; 204 const DeviceModel m_model; 205 206 /* 207 * While the project uses Signal11 portable HIDAPI 208 * library, there's no way of doing it asynchronously, 209 * hence polling. 210 */ 211 const int m_retry_sending_count; 212 const int m_retry_receiving_count; 213 std::chrono::milliseconds m_retry_timeout; 214 std::chrono::milliseconds m_send_receive_delay; 215 std::atomic<hid_device *>mp_devhandle; 216 std::string m_path; 217 218 static std::atomic_int instances_count; 219 static std::chrono::milliseconds default_delay ; 220 }; 221 222 class Stick10 : public Device { 223 public: 224 Stick10(); 225 226 }; 227 228 class Stick20 : public Device { 229 public: 230 Stick20(); 231 }; 232 233 class LibremKey : public Device { 234 public: 235 LibremKey(); 236 }; 237 238 } 239 } 240 #endif 241