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 #include <cstring>
23 #include <iostream>
24 #include "libnitrokey/NitrokeyManager.h"
25 #include "libnitrokey/LibraryException.h"
26 #include <algorithm>
27 #include <unordered_map>
28 #include <stick20_commands.h>
29 #include "libnitrokey/misc.h"
30 #include <mutex>
31 #include "libnitrokey/cxx_semantics.h"
32 #include "libnitrokey/misc.h"
33 #include <functional>
34 #include <stick10_commands.h>
35 
36 std::mutex nitrokey::proto::send_receive_mtx;
37 
38 namespace nitrokey{
39 
40     std::mutex mex_dev_com_manager;
41 
42 #ifndef strndup
43 #ifdef _WIN32
44 #pragma message "Using own strndup"
strndup(const char * str,size_t maxlen)45 char * strndup(const char* str, size_t maxlen){
46   size_t len = strnlen(str, maxlen);
47   char* dup = (char *) malloc(len + 1);
48   memcpy(dup, str, len);
49   dup[len] = 0;
50   return dup;
51 }
52 #endif
53 #endif
54 
55 using nitrokey::misc::strcpyT;
56 
57     template <typename T>
get_payload()58     typename T::CommandPayload get_payload(){
59         //Create, initialize and return by value command payload
60         typename T::CommandPayload st;
61         bzero(&st, sizeof(st));
62         return st;
63     }
64 
65 
66     // package type to auth, auth type [Authorize,UserAuthorize]
67     template <typename S, typename A, typename T>
authorize_packet(T & package,const char * admin_temporary_password,shared_ptr<Device> device)68     void NitrokeyManager::authorize_packet(T &package, const char *admin_temporary_password, shared_ptr<Device> device){
69       if (!is_authorization_command_supported()){
70         LOG("Authorization command not supported, skipping", Loglevel::WARNING);
71       }
72         auto auth = get_payload<A>();
73         strcpyT(auth.temporary_password, admin_temporary_password);
74         auth.crc_to_authorize = S::CommandTransaction::getCRC(package);
75         A::CommandTransaction::run(device, auth);
76     }
77 
78     shared_ptr <NitrokeyManager> NitrokeyManager::_instance = nullptr;
79 
NitrokeyManager()80     NitrokeyManager::NitrokeyManager() : device(nullptr)
81     {
82         set_debug(false);
83     }
~NitrokeyManager()84     NitrokeyManager::~NitrokeyManager() {
85         std::lock_guard<std::mutex> lock(mex_dev_com_manager);
86 
87         for (auto d : connected_devices){
88             if (d.second == nullptr) continue;
89             d.second->disconnect();
90             connected_devices[d.first] = nullptr;
91         }
92     }
93 
set_current_device_speed(int retry_delay,int send_receive_delay)94     bool NitrokeyManager::set_current_device_speed(int retry_delay, int send_receive_delay){
95       if (retry_delay < 20 || send_receive_delay < 20){
96         LOG("Delay set too low: " + to_string(retry_delay) +" "+ to_string(send_receive_delay), Loglevel::WARNING);
97         return false;
98       }
99 
100       std::lock_guard<std::mutex> lock(mex_dev_com_manager);
101       if(device == nullptr) {
102         return false;
103       }
104       device->set_receiving_delay(std::chrono::duration<int, std::milli>(send_receive_delay));
105       device->set_retry_delay(std::chrono::duration<int, std::milli>(retry_delay));
106       return true;
107     }
108 
list_devices()109     std::vector<DeviceInfo> NitrokeyManager::list_devices(){
110         std::lock_guard<std::mutex> lock(mex_dev_com_manager);
111 
112         return Device::enumerate();
113     }
114 
list_devices_by_cpuID()115     std::vector<std::string> NitrokeyManager::list_devices_by_cpuID(){
116         using misc::toHex;
117         //disconnect default device
118         disconnect();
119 
120         std::lock_guard<std::mutex> lock(mex_dev_com_manager);
121         LOGD1("Disconnecting registered devices");
122         for (auto & kv : connected_devices_byID){
123             if (kv.second != nullptr)
124                 kv.second->disconnect();
125         }
126         connected_devices_byID.clear();
127 
128         LOGD1("Enumerating devices");
129         std::vector<std::string> res;
130         const auto v = Device::enumerate();
131         LOGD1("Discovering IDs");
132         for (auto & i: v){
133             if (i.m_deviceModel != DeviceModel::STORAGE)
134                 continue;
135             auto p = i.m_path;
136             auto d = make_shared<Stick20>();
137             LOGD1( std::string("Found: ") + p );
138             d->set_path(p);
139             try{
140                 if (d->connect()){
141                     device = d;
142                     std::string id;
143                     try {
144                         const auto status = get_status_storage();
145                         const auto sc_id = toHex(status.ActiveSmartCardID_u32);
146                         const auto sd_id = toHex(status.ActiveSD_CardID_u32);
147                         id += sc_id + ":" + sd_id;
148                         id += "_p_" + p;
149                     }
150                     catch (const LongOperationInProgressException &e) {
151                         LOGD1(std::string("Long operation in progress, setting ID to: ") + p);
152                         id = p;
153                     }
154 
155                     connected_devices_byID[id] = d;
156                     res.push_back(id);
157                     LOGD1( std::string("Found: ") + p + " => " + id);
158                 } else{
159                     LOGD1( std::string("Could not connect to: ") + p);
160                 }
161             }
162             catch (const DeviceCommunicationException &e){
163                 LOGD1( std::string("Exception encountered: ") + p);
164             }
165         }
166         return res;
167     }
168 
connect_with_ID(const std::string id)169     bool NitrokeyManager::connect_with_ID(const std::string id) {
170         std::lock_guard<std::mutex> lock(mex_dev_com_manager);
171 
172         auto position = connected_devices_byID.find(id);
173         if (position == connected_devices_byID.end()) {
174             LOGD1(std::string("Could not find device ")+id + ". Refresh devices list with list_devices_by_cpuID().");
175             return false;
176         }
177 
178         auto d = connected_devices_byID[id];
179         device = d;
180         current_device_id = id;
181 
182         //validate connection
183         try{
184             get_status();
185         }
186         catch (const LongOperationInProgressException &){
187             //ignore
188         }
189         catch (const DeviceCommunicationException &){
190             d->disconnect();
191             current_device_id = "";
192             connected_devices_byID[id] = nullptr;
193             connected_devices_byID.erase(position);
194             return false;
195         }
196         nitrokey::log::Log::setPrefix(id);
197         LOGD1("Device successfully changed");
198         return true;
199     }
200 
201         /**
202          * Connects device to path.
203          * Assumes devices are not being disconnected and caches connections (param cache_connections).
204          * @param path os-dependent device path
205          * @return false, when could not connect, true otherwise
206          */
connect_with_path(std::string path)207     bool NitrokeyManager::connect_with_path(std::string path) {
208         const bool cache_connections = false;
209 
210         std::lock_guard<std::mutex> lock(mex_dev_com_manager);
211 
212         if (cache_connections){
213             if(connected_devices.find(path) != connected_devices.end()
214                     && connected_devices[path] != nullptr) {
215                 device = connected_devices[path];
216                 return true;
217             }
218         }
219 
220 	auto vendor_id = NITROKEY_VID;
221         auto info_ptr = hid_enumerate(vendor_id, 0);
222 	if (!info_ptr) {
223 	  vendor_id = PURISM_VID;
224 	  info_ptr = hid_enumerate(vendor_id, 0);
225 	}
226         auto first_info_ptr = info_ptr;
227         if (!info_ptr)
228           return false;
229 
230         misc::Option<DeviceModel> model;
231         while (info_ptr && !model.has_value()) {
232             if (path == std::string(info_ptr->path)) {
233                 model = product_id_to_model(info_ptr->vendor_id, info_ptr->product_id);
234             }
235             info_ptr = info_ptr->next;
236         }
237         hid_free_enumeration(first_info_ptr);
238 
239         if (!model.has_value())
240             return false;
241 
242         auto p = Device::create(model.value());
243         if (!p)
244             return false;
245         p->set_path(path);
246 
247         if(!p->connect()) return false;
248 
249         if(cache_connections){
250             connected_devices [path] = p;
251         }
252 
253         device = p; //previous device will be disconnected automatically
254         current_device_id = path;
255         nitrokey::log::Log::setPrefix(path);
256         LOGD1("Device successfully changed");
257         return true;
258     }
259 
connect()260     bool NitrokeyManager::connect() {
261         std::lock_guard<std::mutex> lock(mex_dev_com_manager);
262         vector< shared_ptr<Device> > devices = { make_shared<Stick10>(), make_shared<Stick20>(),
263 						 make_shared<LibremKey>() };
264         bool connected = false;
265         for( auto & d : devices ){
266             if (d->connect()){
267                 device = std::shared_ptr<Device>(d);
268                 connected = true;
269             }
270         }
271         return connected;
272     }
273 
274 
set_log_function(std::function<void (std::string)> log_function)275     void NitrokeyManager::set_log_function(std::function<void(std::string)> log_function){
276       static nitrokey::log::FunctionalLogHandler handler(log_function);
277       nitrokey::log::Log::instance().set_handler(&handler);
278     }
279 
set_default_commands_delay(int delay)280     bool NitrokeyManager::set_default_commands_delay(int delay){
281       if (delay < 20){
282         LOG("Delay set too low: " + to_string(delay), Loglevel::WARNING);
283         return false;
284       }
285       Device::set_default_device_speed(delay);
286       return true;
287     }
288 
connect(const char * device_model)289     bool NitrokeyManager::connect(const char *device_model) {
290       std::lock_guard<std::mutex> lock(mex_dev_com_manager);
291       LOG(__FUNCTION__, nitrokey::log::Loglevel::DEBUG_L2);
292       switch (device_model[0]){
293             case 'P':
294                 device = make_shared<Stick10>();
295                 break;
296             case 'S':
297                 device = make_shared<Stick20>();
298                 break;
299             case 'L':
300                 device = make_shared<LibremKey>();
301                 break;
302             default:
303                 throw std::runtime_error("Unknown model");
304         }
305         return device->connect();
306     }
307 
connect(device::DeviceModel device_model)308     bool NitrokeyManager::connect(device::DeviceModel device_model) {
309         const char *model_string;
310         switch (device_model) {
311             case device::DeviceModel::PRO:
312                 model_string = "P";
313                 break;
314             case device::DeviceModel::STORAGE:
315                 model_string = "S";
316                 break;
317             case device::DeviceModel::LIBREM:
318                 model_string = "L";
319                 break;
320             default:
321                 throw std::runtime_error("Unknown model");
322         }
323         return connect(model_string);
324     }
325 
instance()326     shared_ptr<NitrokeyManager> NitrokeyManager::instance() {
327       static std::mutex mutex;
328       std::lock_guard<std::mutex> lock(mutex);
329         if (_instance == nullptr){
330             _instance = make_shared<NitrokeyManager>();
331         }
332         return _instance;
333     }
334 
335 
336 
disconnect()337     bool NitrokeyManager::disconnect() {
338       std::lock_guard<std::mutex> lock(mex_dev_com_manager);
339       return _disconnect_no_lock();
340     }
341 
_disconnect_no_lock()342   bool NitrokeyManager::_disconnect_no_lock() {
343     //do not use directly without locked mutex,
344     //used by could_be_enumerated, disconnect
345     if (device == nullptr){
346       return false;
347     }
348     const auto res = device->disconnect();
349     device = nullptr;
350     return res;
351   }
352 
is_connected()353   bool NitrokeyManager::is_connected() throw(){
354       std::lock_guard<std::mutex> lock(mex_dev_com_manager);
355       if(device != nullptr){
356         auto connected = device->could_be_enumerated();
357         if(connected){
358           return true;
359         } else {
360           _disconnect_no_lock();
361           return false;
362         }
363       }
364       return false;
365   }
366 
could_current_device_be_enumerated()367   bool NitrokeyManager::could_current_device_be_enumerated() {
368     std::lock_guard<std::mutex> lock(mex_dev_com_manager);
369     if (device != nullptr) {
370       return device->could_be_enumerated();
371     }
372     return false;
373   }
374 
set_loglevel(int loglevel)375     void NitrokeyManager::set_loglevel(int loglevel) {
376       loglevel = max(loglevel, static_cast<int>(Loglevel::ERROR));
377       loglevel = min(loglevel, static_cast<int>(Loglevel::DEBUG_L2));
378       Log::instance().set_loglevel(static_cast<Loglevel>(loglevel));
379     }
380 
set_loglevel(Loglevel loglevel)381     void NitrokeyManager::set_loglevel(Loglevel loglevel) {
382       Log::instance().set_loglevel(loglevel);
383     }
384 
set_debug(bool state)385     void NitrokeyManager::set_debug(bool state) {
386         if (state){
387             Log::instance().set_loglevel(Loglevel::DEBUG);
388         } else {
389             Log::instance().set_loglevel(Loglevel::ERROR);
390         }
391     }
392 
393 
get_serial_number()394     string NitrokeyManager::get_serial_number() {
395       try {
396         auto serial_number = this->get_serial_number_as_u32();
397         if (serial_number == 0) {
398           return "NA";
399         } else {
400           return nitrokey::misc::toHex(serial_number);
401         }
402       } catch (DeviceNotConnected& e) {
403         return "";
404       }
405     }
406 
get_serial_number_as_u32()407     uint32_t NitrokeyManager::get_serial_number_as_u32() {
408         if (device == nullptr) { throw DeviceNotConnected("device not connected"); }
409       switch (device->get_device_model()) {
410         case DeviceModel::LIBREM:
411         case DeviceModel::PRO: {
412           auto response = GetStatus::CommandTransaction::run(device);
413           return response.data().card_serial_u32;
414         }
415           break;
416 
417         case DeviceModel::STORAGE:
418         {
419           auto response = stick20::GetDeviceStatus::CommandTransaction::run(device);
420           return response.data().ActiveSmartCardID_u32;
421         }
422           break;
423       }
424       return 0;
425     }
426 
get_status()427     stick10::GetStatus::ResponsePayload NitrokeyManager::get_status(){
428       try{
429         auto response = GetStatus::CommandTransaction::run(device);
430         return response.data();
431       }
432       catch (DeviceSendingFailure &e){
433 //        disconnect();
434         throw;
435       }
436     }
437 
get_status_as_string()438     string NitrokeyManager::get_status_as_string() {
439         auto response = GetStatus::CommandTransaction::run(device);
440         return response.data().dissect();
441     }
442 
getFilledOTPCode(uint32_t code,bool use_8_digits)443     string getFilledOTPCode(uint32_t code, bool use_8_digits){
444       stringstream s;
445       s << std::right << std::setw(use_8_digits ? 8 : 6) << std::setfill('0') << code;
446       return s.str();
447     }
448 
get_HOTP_code(uint8_t slot_number,const char * user_temporary_password)449     string NitrokeyManager::get_HOTP_code(uint8_t slot_number, const char *user_temporary_password) {
450       if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
451 
452       if (is_authorization_command_supported()){
453         auto gh = get_payload<GetHOTP>();
454         gh.slot_number = get_internal_slot_number_for_hotp(slot_number);
455         if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0){ //FIXME use string instead of strlen
456             authorize_packet<GetHOTP, UserAuthorize>(gh, user_temporary_password, device);
457         }
458         auto resp = GetHOTP::CommandTransaction::run(device, gh);
459         return getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
460       } else {
461         auto gh = get_payload<stick10_08::GetHOTP>();
462         gh.slot_number = get_internal_slot_number_for_hotp(slot_number);
463         if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0) {
464           strcpyT(gh.temporary_user_password, user_temporary_password);
465         }
466         auto resp = stick10_08::GetHOTP::CommandTransaction::run(device, gh);
467         return getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
468       }
469       return "";
470     }
471 
is_internal_hotp_slot_number(uint8_t slot_number) const472     bool NitrokeyManager::is_internal_hotp_slot_number(uint8_t slot_number) const { return slot_number < 0x20; }
is_valid_hotp_slot_number(uint8_t slot_number) const473     bool NitrokeyManager::is_valid_hotp_slot_number(uint8_t slot_number) const { return slot_number < 3; }
is_valid_totp_slot_number(uint8_t slot_number) const474     bool NitrokeyManager::is_valid_totp_slot_number(uint8_t slot_number) const { return slot_number < 0x10-1; } //15
get_internal_slot_number_for_totp(uint8_t slot_number) const475     uint8_t NitrokeyManager::get_internal_slot_number_for_totp(uint8_t slot_number) const { return (uint8_t) (0x20 + slot_number); }
get_internal_slot_number_for_hotp(uint8_t slot_number) const476     uint8_t NitrokeyManager::get_internal_slot_number_for_hotp(uint8_t slot_number) const { return (uint8_t) (0x10 + slot_number); }
477 
478 
479 
get_TOTP_code(uint8_t slot_number,uint64_t challenge,uint64_t last_totp_time,uint8_t last_interval,const char * user_temporary_password)480     string NitrokeyManager::get_TOTP_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time,
481                                           uint8_t last_interval,
482                                           const char *user_temporary_password) {
483         if(!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
484         slot_number = get_internal_slot_number_for_totp(slot_number);
485 
486         if (is_authorization_command_supported()){
487           auto gt = get_payload<GetTOTP>();
488           gt.slot_number = slot_number;
489           gt.challenge = challenge;
490           gt.last_interval = last_interval;
491           gt.last_totp_time = last_totp_time;
492 
493           if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0){ //FIXME use string instead of strlen
494               authorize_packet<GetTOTP, UserAuthorize>(gt, user_temporary_password, device);
495           }
496           auto resp = GetTOTP::CommandTransaction::run(device, gt);
497           return getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
498         } else {
499           auto gt = get_payload<stick10_08::GetTOTP>();
500           strcpyT(gt.temporary_user_password, user_temporary_password);
501           gt.slot_number = slot_number;
502           auto resp = stick10_08::GetTOTP::CommandTransaction::run(device, gt);
503           return getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
504         }
505       return "";
506     }
507 
erase_slot(uint8_t slot_number,const char * temporary_password)508     bool NitrokeyManager::erase_slot(uint8_t slot_number, const char *temporary_password) {
509       if (is_authorization_command_supported()){
510         auto p = get_payload<EraseSlot>();
511         p.slot_number = slot_number;
512         authorize_packet<EraseSlot, Authorize>(p, temporary_password, device);
513         auto resp = EraseSlot::CommandTransaction::run(device,p);
514       } else {
515         auto p = get_payload<stick10_08::EraseSlot>();
516         p.slot_number = slot_number;
517         strcpyT(p.temporary_admin_password, temporary_password);
518         auto resp = stick10_08::EraseSlot::CommandTransaction::run(device,p);
519       }
520         return true;
521     }
522 
erase_hotp_slot(uint8_t slot_number,const char * temporary_password)523     bool NitrokeyManager::erase_hotp_slot(uint8_t slot_number, const char *temporary_password) {
524         if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
525         slot_number = get_internal_slot_number_for_hotp(slot_number);
526         return erase_slot(slot_number, temporary_password);
527     }
528 
erase_totp_slot(uint8_t slot_number,const char * temporary_password)529     bool NitrokeyManager::erase_totp_slot(uint8_t slot_number, const char *temporary_password) {
530         if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
531         slot_number = get_internal_slot_number_for_totp(slot_number);
532         return erase_slot(slot_number, temporary_password);
533     }
534 
535     template <typename T, typename U>
vector_copy_ranged(T & dest,std::vector<U> & vec,size_t begin,size_t elements_to_copy)536     void vector_copy_ranged(T& dest, std::vector<U> &vec, size_t begin, size_t elements_to_copy){
537         const size_t d_size = sizeof(dest);
538       if(d_size < elements_to_copy){
539             throw TargetBufferSmallerThanSource(elements_to_copy, d_size);
540         }
541         std::fill(dest, dest+d_size, 0);
542         std::copy(vec.begin() + begin, vec.begin() +begin + elements_to_copy, dest);
543     }
544 
545     template <typename T, typename U>
vector_copy(T & dest,std::vector<U> & vec)546     void vector_copy(T& dest, std::vector<U> &vec){
547         const size_t d_size = sizeof(dest);
548         if(d_size < vec.size()){
549             throw TargetBufferSmallerThanSource(vec.size(), d_size);
550         }
551         std::fill(dest, dest+d_size, 0);
552         std::copy(vec.begin(), vec.end(), dest);
553     }
554 
write_HOTP_slot(uint8_t slot_number,const char * slot_name,const char * secret,uint64_t hotp_counter,bool use_8_digits,bool use_enter,bool use_tokenID,const char * token_ID,const char * temporary_password)555     bool NitrokeyManager::write_HOTP_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint64_t hotp_counter,
556                                           bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID,
557                                           const char *temporary_password) {
558         if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
559 
560       int internal_slot_number = get_internal_slot_number_for_hotp(slot_number);
561       if (is_authorization_command_supported()){
562         write_HOTP_slot_authorize(internal_slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID,
563                     token_ID, temporary_password);
564       } else {
565         write_OTP_slot_no_authorize(internal_slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID,
566                                     token_ID, temporary_password);
567       }
568       return true;
569     }
570 
write_HOTP_slot_authorize(uint8_t slot_number,const char * slot_name,const char * secret,uint64_t hotp_counter,bool use_8_digits,bool use_enter,bool use_tokenID,const char * token_ID,const char * temporary_password)571     void NitrokeyManager::write_HOTP_slot_authorize(uint8_t slot_number, const char *slot_name, const char *secret,
572                                                     uint64_t hotp_counter, bool use_8_digits, bool use_enter,
573                                                     bool use_tokenID, const char *token_ID, const char *temporary_password) {
574       auto payload = get_payload<WriteToHOTPSlot>();
575       payload.slot_number = slot_number;
576       auto secret_bin = misc::hex_string_to_byte(secret);
577       vector_copy(payload.slot_secret, secret_bin);
578       strcpyT(payload.slot_name, slot_name);
579       strcpyT(payload.slot_token_id, token_ID);
580       switch (device->get_device_model() ){
581         case DeviceModel::LIBREM:
582         case DeviceModel::PRO: {
583           payload.slot_counter = hotp_counter;
584           break;
585         }
586         case DeviceModel::STORAGE: {
587           string counter = to_string(hotp_counter);
588           strcpyT(payload.slot_counter_s, counter.c_str());
589           break;
590         }
591         default:
592           LOG(string(__FILE__) + to_string(__LINE__) +
593                           string(__FUNCTION__) + string(" Unhandled device model for HOTP")
594               , Loglevel::DEBUG);
595           break;
596       }
597       payload.use_8_digits = use_8_digits;
598       payload.use_enter = use_enter;
599       payload.use_tokenID = use_tokenID;
600 
601       authorize_packet<WriteToHOTPSlot, Authorize>(payload, temporary_password, device);
602 
603       auto resp = WriteToHOTPSlot::CommandTransaction::run(device, payload);
604     }
605 
write_TOTP_slot(uint8_t slot_number,const char * slot_name,const char * secret,uint16_t time_window,bool use_8_digits,bool use_enter,bool use_tokenID,const char * token_ID,const char * temporary_password)606     bool NitrokeyManager::write_TOTP_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint16_t time_window,
607                                               bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID,
608                                               const char *temporary_password) {
609         if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
610        int internal_slot_number = get_internal_slot_number_for_totp(slot_number);
611 
612       if (is_authorization_command_supported()){
613       write_TOTP_slot_authorize(internal_slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID,
614                                 token_ID, temporary_password);
615       } else {
616         write_OTP_slot_no_authorize(internal_slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID,
617                                     token_ID, temporary_password);
618       }
619 
620       return true;
621     }
622 
write_OTP_slot_no_authorize(uint8_t internal_slot_number,const char * slot_name,const char * secret,uint64_t counter_or_interval,bool use_8_digits,bool use_enter,bool use_tokenID,const char * token_ID,const char * temporary_password) const623     void NitrokeyManager::write_OTP_slot_no_authorize(uint8_t internal_slot_number, const char *slot_name,
624                                                       const char *secret,
625                                                       uint64_t counter_or_interval, bool use_8_digits, bool use_enter,
626                                                       bool use_tokenID, const char *token_ID,
627                                                       const char *temporary_password) const {
628 
629       auto payload2 = get_payload<stick10_08::SendOTPData>();
630       strcpyT(payload2.temporary_admin_password, temporary_password);
631       strcpyT(payload2.data, slot_name);
632       payload2.setTypeName();
633       stick10_08::SendOTPData::CommandTransaction::run(device, payload2);
634 
635       payload2.setTypeSecret();
636       payload2.id = 0;
637       auto secret_bin = misc::hex_string_to_byte(secret);
638       auto remaining_secret_length = secret_bin.size();
639       const auto maximum_OTP_secret_size = 40;
640       if(remaining_secret_length > maximum_OTP_secret_size){
641         throw TargetBufferSmallerThanSource(remaining_secret_length, maximum_OTP_secret_size);
642       }
643 
644       while (remaining_secret_length>0){
645         const auto bytesToCopy = std::min(sizeof(payload2.data), remaining_secret_length);
646         const auto start = secret_bin.size() - remaining_secret_length;
647         memset(payload2.data, 0, sizeof(payload2.data));
648         vector_copy_ranged(payload2.data, secret_bin, start, bytesToCopy);
649         stick10_08::SendOTPData::CommandTransaction::run(device, payload2);
650         remaining_secret_length -= bytesToCopy;
651         payload2.id++;
652       }
653 
654       auto payload = get_payload<stick10_08::WriteToOTPSlot>();
655       strcpyT(payload.temporary_admin_password, temporary_password);
656       strcpyT(payload.slot_token_id, token_ID);
657       payload.use_8_digits = use_8_digits;
658       payload.use_enter = use_enter;
659       payload.use_tokenID = use_tokenID;
660       payload.slot_counter_or_interval = counter_or_interval;
661       payload.slot_number = internal_slot_number;
662       stick10_08::WriteToOTPSlot::CommandTransaction::run(device, payload);
663     }
664 
write_TOTP_slot_authorize(uint8_t slot_number,const char * slot_name,const char * secret,uint16_t time_window,bool use_8_digits,bool use_enter,bool use_tokenID,const char * token_ID,const char * temporary_password)665     void NitrokeyManager::write_TOTP_slot_authorize(uint8_t slot_number, const char *slot_name, const char *secret,
666                                                     uint16_t time_window, bool use_8_digits, bool use_enter,
667                                                     bool use_tokenID, const char *token_ID, const char *temporary_password) {
668       auto payload = get_payload<WriteToTOTPSlot>();
669       payload.slot_number = slot_number;
670       auto secret_bin = misc::hex_string_to_byte(secret);
671       vector_copy(payload.slot_secret, secret_bin);
672       strcpyT(payload.slot_name, slot_name);
673       strcpyT(payload.slot_token_id, token_ID);
674       payload.slot_interval = time_window; //FIXME naming
675       payload.use_8_digits = use_8_digits;
676       payload.use_enter = use_enter;
677       payload.use_tokenID = use_tokenID;
678 
679       authorize_packet<WriteToTOTPSlot, Authorize>(payload, temporary_password, device);
680 
681       auto resp = WriteToTOTPSlot::CommandTransaction::run(device, payload);
682     }
683 
get_totp_slot_name(uint8_t slot_number)684     char * NitrokeyManager::get_totp_slot_name(uint8_t slot_number) {
685         if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
686         slot_number = get_internal_slot_number_for_totp(slot_number);
687         return get_slot_name(slot_number);
688     }
get_hotp_slot_name(uint8_t slot_number)689     char * NitrokeyManager::get_hotp_slot_name(uint8_t slot_number) {
690         if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
691         slot_number = get_internal_slot_number_for_hotp(slot_number);
692         return get_slot_name(slot_number);
693     }
694 
695   static const int max_string_field_length = 2*1024; //storage's status string is ~1k
696 
get_slot_name(uint8_t slot_number)697   char * NitrokeyManager::get_slot_name(uint8_t slot_number)  {
698         auto payload = get_payload<GetSlotName>();
699         payload.slot_number = slot_number;
700         auto resp = GetSlotName::CommandTransaction::run(device, payload);
701         return strndup((const char *) resp.data().slot_name, max_string_field_length);
702     }
703 
first_authenticate(const char * pin,const char * temporary_password)704     bool NitrokeyManager::first_authenticate(const char *pin, const char *temporary_password) {
705         auto authreq = get_payload<FirstAuthenticate>();
706         strcpyT(authreq.card_password, pin);
707         strcpyT(authreq.temporary_password, temporary_password);
708         FirstAuthenticate::CommandTransaction::run(device, authreq);
709         return true;
710     }
711 
set_time(uint64_t time)712     bool NitrokeyManager::set_time(uint64_t time) {
713         auto p = get_payload<SetTime>();
714         p.reset = 1;
715         p.time = time;
716         SetTime::CommandTransaction::run(device, p);
717         return false;
718     }
719 
set_time_soft(uint64_t time)720     void NitrokeyManager::set_time_soft(uint64_t time) {
721         auto p = get_payload<SetTime>();
722         p.reset = 0;
723         p.time = time;
724         SetTime::CommandTransaction::run(device, p);
725     }
726 
get_time(uint64_t time)727     bool NitrokeyManager::get_time(uint64_t time) {
728         set_time_soft(time);
729         return true;
730     }
731 
change_user_PIN(const char * current_PIN,const char * new_PIN)732     void NitrokeyManager::change_user_PIN(const char *current_PIN, const char *new_PIN) {
733         change_PIN_general<ChangeUserPin, PasswordKind::User>(current_PIN, new_PIN);
734     }
735 
change_admin_PIN(const char * current_PIN,const char * new_PIN)736     void NitrokeyManager::change_admin_PIN(const char *current_PIN, const char *new_PIN) {
737         change_PIN_general<ChangeAdminPin, PasswordKind::Admin>(current_PIN, new_PIN);
738     }
739 
740     template <typename ProCommand, PasswordKind StoKind>
change_PIN_general(const char * current_PIN,const char * new_PIN)741     void NitrokeyManager::change_PIN_general(const char *current_PIN, const char *new_PIN) {
742         switch (device->get_device_model()){
743             case DeviceModel::LIBREM:
744             case DeviceModel::PRO:
745             {
746                 auto p = get_payload<ProCommand>();
747                 strcpyT(p.old_pin, current_PIN);
748                 strcpyT(p.new_pin, new_PIN);
749                 ProCommand::CommandTransaction::run(device, p);
750             }
751                 break;
752             //in Storage change admin/user pin is divided to two commands with 20 chars field len
753             case DeviceModel::STORAGE:
754             {
755                 auto p = get_payload<ChangeAdminUserPin20Current>();
756                 strcpyT(p.password, current_PIN);
757                 p.set_kind(StoKind);
758                 auto p2 = get_payload<ChangeAdminUserPin20New>();
759                 strcpyT(p2.password, new_PIN);
760                 p2.set_kind(StoKind);
761                 ChangeAdminUserPin20Current::CommandTransaction::run(device, p);
762                 ChangeAdminUserPin20New::CommandTransaction::run(device, p2);
763             }
764                 break;
765         }
766 
767     }
768 
enable_password_safe(const char * user_pin)769     void NitrokeyManager::enable_password_safe(const char *user_pin) {
770         //The following command will cancel enabling PWS if it is not supported
771         auto a = get_payload<IsAESSupported>();
772         strcpyT(a.user_password, user_pin);
773         IsAESSupported::CommandTransaction::run(device, a);
774 
775         auto p = get_payload<EnablePasswordSafe>();
776         strcpyT(p.user_password, user_pin);
777         EnablePasswordSafe::CommandTransaction::run(device, p);
778     }
779 
get_password_safe_slot_status()780     vector <uint8_t> NitrokeyManager::get_password_safe_slot_status() {
781         auto responsePayload = GetPasswordSafeSlotStatus::CommandTransaction::run(device);
782         vector<uint8_t> v = vector<uint8_t>(responsePayload.data().password_safe_status,
783                                             responsePayload.data().password_safe_status
784                                             + sizeof(responsePayload.data().password_safe_status));
785         return v;
786     }
787 
get_user_retry_count()788     uint8_t NitrokeyManager::get_user_retry_count() {
789         if(device->get_device_model() == DeviceModel::STORAGE){
790           stick20::GetDeviceStatus::CommandTransaction::run(device);
791         }
792         auto response = GetUserPasswordRetryCount::CommandTransaction::run(device);
793         return response.data().password_retry_count;
794     }
795 
get_admin_retry_count()796     uint8_t NitrokeyManager::get_admin_retry_count() {
797         if(device->get_device_model() == DeviceModel::STORAGE){
798           stick20::GetDeviceStatus::CommandTransaction::run(device);
799         }
800         auto response = GetPasswordRetryCount::CommandTransaction::run(device);
801         return response.data().password_retry_count;
802     }
803 
lock_device()804     void NitrokeyManager::lock_device() {
805         LockDevice::CommandTransaction::run(device);
806     }
807 
get_password_safe_slot_name(uint8_t slot_number)808     char * NitrokeyManager::get_password_safe_slot_name(uint8_t slot_number) {
809         if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number);
810         auto p = get_payload<GetPasswordSafeSlotName>();
811         p.slot_number = slot_number;
812         auto response = GetPasswordSafeSlotName::CommandTransaction::run(device, p);
813         return strndup((const char *) response.data().slot_name, max_string_field_length);
814     }
815 
is_valid_password_safe_slot_number(uint8_t slot_number) const816     bool NitrokeyManager::is_valid_password_safe_slot_number(uint8_t slot_number) const { return slot_number < 16; }
817 
get_password_safe_slot_login(uint8_t slot_number)818     char * NitrokeyManager::get_password_safe_slot_login(uint8_t slot_number) {
819         if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number);
820         auto p = get_payload<GetPasswordSafeSlotLogin>();
821         p.slot_number = slot_number;
822         auto response = GetPasswordSafeSlotLogin::CommandTransaction::run(device, p);
823         return strndup((const char *) response.data().slot_login, max_string_field_length);
824     }
825 
get_password_safe_slot_password(uint8_t slot_number)826     char * NitrokeyManager::get_password_safe_slot_password(uint8_t slot_number) {
827         if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number);
828         auto p = get_payload<GetPasswordSafeSlotPassword>();
829         p.slot_number = slot_number;
830         auto response = GetPasswordSafeSlotPassword::CommandTransaction::run(device, p);
831         return strndup((const char *) response.data().slot_password, max_string_field_length); //FIXME use secure way
832     }
833 
write_password_safe_slot(uint8_t slot_number,const char * slot_name,const char * slot_login,const char * slot_password)834     void NitrokeyManager::write_password_safe_slot(uint8_t slot_number, const char *slot_name, const char *slot_login,
835                                                        const char *slot_password) {
836         if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number);
837         auto p = get_payload<SetPasswordSafeSlotData>();
838         p.slot_number = slot_number;
839         strcpyT(p.slot_name, slot_name);
840         strcpyT(p.slot_password, slot_password);
841         SetPasswordSafeSlotData::CommandTransaction::run(device, p);
842 
843         auto p2 = get_payload<SetPasswordSafeSlotData2>();
844         p2.slot_number = slot_number;
845         strcpyT(p2.slot_login_name, slot_login);
846         SetPasswordSafeSlotData2::CommandTransaction::run(device, p2);
847     }
848 
erase_password_safe_slot(uint8_t slot_number)849     void NitrokeyManager::erase_password_safe_slot(uint8_t slot_number) {
850         if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number);
851         auto p = get_payload<ErasePasswordSafeSlot>();
852         p.slot_number = slot_number;
853         ErasePasswordSafeSlot::CommandTransaction::run(device, p);
854     }
855 
user_authenticate(const char * user_password,const char * temporary_password)856     void NitrokeyManager::user_authenticate(const char *user_password, const char *temporary_password) {
857         auto p = get_payload<UserAuthenticate>();
858         strcpyT(p.card_password, user_password);
859         strcpyT(p.temporary_password, temporary_password);
860         UserAuthenticate::CommandTransaction::run(device, p);
861     }
862 
build_aes_key(const char * admin_password)863     void NitrokeyManager::build_aes_key(const char *admin_password) {
864         switch (device->get_device_model()) {
865             case DeviceModel::LIBREM:
866             case DeviceModel::PRO: {
867                 auto p = get_payload<BuildAESKey>();
868                 strcpyT(p.admin_password, admin_password);
869                 BuildAESKey::CommandTransaction::run(device, p);
870                 break;
871             }
872             case DeviceModel::STORAGE : {
873                 auto p = get_payload<stick20::CreateNewKeys>();
874                 strcpyT(p.password, admin_password);
875                 p.set_defaults();
876                 stick20::CreateNewKeys::CommandTransaction::run(device, p);
877                 break;
878             }
879         }
880     }
881 
factory_reset(const char * admin_password)882     void NitrokeyManager::factory_reset(const char *admin_password) {
883         auto p = get_payload<FactoryReset>();
884         strcpyT(p.admin_password, admin_password);
885         FactoryReset::CommandTransaction::run(device, p);
886     }
887 
unlock_user_password(const char * admin_password,const char * new_user_password)888     void NitrokeyManager::unlock_user_password(const char *admin_password, const char *new_user_password) {
889       switch (device->get_device_model()){
890         case DeviceModel::LIBREM:
891         case DeviceModel::PRO: {
892           auto p = get_payload<stick10::UnlockUserPassword>();
893           strcpyT(p.admin_password, admin_password);
894           strcpyT(p.user_new_password, new_user_password);
895           stick10::UnlockUserPassword::CommandTransaction::run(device, p);
896           break;
897         }
898         case DeviceModel::STORAGE : {
899           auto p2 = get_payload<ChangeAdminUserPin20Current>();
900           p2.set_defaults();
901           strcpyT(p2.password, admin_password);
902           ChangeAdminUserPin20Current::CommandTransaction::run(device, p2);
903           auto p3 = get_payload<stick20::UnlockUserPin>();
904           p3.set_defaults();
905           strcpyT(p3.password, new_user_password);
906           stick20::UnlockUserPin::CommandTransaction::run(device, p3);
907           break;
908         }
909       }
910     }
911 
912 
write_config(uint8_t numlock,uint8_t capslock,uint8_t scrolllock,bool enable_user_password,bool delete_user_password,const char * admin_temporary_password)913     void NitrokeyManager::write_config(uint8_t numlock, uint8_t capslock, uint8_t scrolllock, bool enable_user_password,
914                                        bool delete_user_password, const char *admin_temporary_password) {
915         auto p = get_payload<stick10_08::WriteGeneralConfig>();
916         p.numlock = numlock;
917         p.capslock = capslock;
918         p.scrolllock = scrolllock;
919         p.enable_user_password = static_cast<uint8_t>(enable_user_password ? 1 : 0);
920         p.delete_user_password = static_cast<uint8_t>(delete_user_password ? 1 : 0);
921         if (is_authorization_command_supported()){
922           authorize_packet<stick10_08::WriteGeneralConfig, Authorize>(p, admin_temporary_password, device);
923         } else {
924           strcpyT(p.temporary_admin_password, admin_temporary_password);
925         }
926         stick10_08::WriteGeneralConfig::CommandTransaction::run(device, p);
927     }
928 
read_config()929     vector<uint8_t> NitrokeyManager::read_config() {
930         auto responsePayload = GetStatus::CommandTransaction::run(device);
931         vector<uint8_t> v = vector<uint8_t>(responsePayload.data().general_config,
932                                             responsePayload.data().general_config+sizeof(responsePayload.data().general_config));
933         return v;
934     }
935 
is_authorization_command_supported()936     bool NitrokeyManager::is_authorization_command_supported(){
937       //authorization command is supported for versions equal or below:
938         auto m = std::unordered_map<DeviceModel , int, EnumClassHash>({
939                                                {DeviceModel::PRO, 7},
940                                                {DeviceModel::LIBREM, 7},
941                                                {DeviceModel::STORAGE, 53},
942          });
943         return get_minor_firmware_version() <= m[device->get_device_model()];
944     }
945 
is_320_OTP_secret_supported()946     bool NitrokeyManager::is_320_OTP_secret_supported(){
947         // 320 bit OTP secret is supported by version bigger or equal to:
948         auto m = std::unordered_map<DeviceModel , int, EnumClassHash>({
949                                                {DeviceModel::PRO, 8},
950                                                {DeviceModel::LIBREM, 8},
951                                                {DeviceModel::STORAGE, 54},
952          });
953         return get_minor_firmware_version() >= m[device->get_device_model()];
954     }
955 
get_connected_device_model() const956     DeviceModel NitrokeyManager::get_connected_device_model() const{
957         if (device == nullptr){
958             throw DeviceNotConnected("device not connected");
959         }
960       return device->get_device_model();
961     }
962 
is_smartcard_in_use()963     bool NitrokeyManager::is_smartcard_in_use(){
964       try{
965         stick20::CheckSmartcardUsage::CommandTransaction::run(device);
966       }
967       catch(const CommandFailedException & e){
968         return e.reason_smartcard_busy();
969       }
970       return false;
971     }
972 
get_minor_firmware_version()973     uint8_t NitrokeyManager::get_minor_firmware_version(){
974       switch(device->get_device_model()){
975         case DeviceModel::LIBREM:
976         case DeviceModel::PRO:{
977           auto status_p = GetStatus::CommandTransaction::run(device);
978           return status_p.data().firmware_version_st.minor; //7 or 8
979         }
980         case DeviceModel::STORAGE:{
981           auto status = stick20::GetDeviceStatus::CommandTransaction::run(device);
982           auto test_firmware = status.data().versionInfo.build_iteration != 0;
983           if (test_firmware)
984             LOG("Development firmware detected. Increasing minor version number.", nitrokey::log::Loglevel::WARNING);
985           return status.data().versionInfo.minor + (test_firmware? 1 : 0);
986         }
987       }
988       return 0;
989     }
get_major_firmware_version()990     uint8_t NitrokeyManager::get_major_firmware_version(){
991       switch(device->get_device_model()){
992         case DeviceModel::LIBREM:
993         case DeviceModel::PRO:{
994           auto status_p = GetStatus::CommandTransaction::run(device);
995           return status_p.data().firmware_version_st.major; //0
996         }
997         case DeviceModel::STORAGE:{
998           auto status = stick20::GetDeviceStatus::CommandTransaction::run(device);
999           return status.data().versionInfo.major;
1000         }
1001       }
1002       return 0;
1003     }
1004 
is_AES_supported(const char * user_password)1005     bool NitrokeyManager::is_AES_supported(const char *user_password) {
1006         auto a = get_payload<IsAESSupported>();
1007         strcpyT(a.user_password, user_password);
1008         IsAESSupported::CommandTransaction::run(device, a);
1009         return true;
1010     }
1011 
1012     //storage commands
1013 
send_startup(uint64_t seconds_from_epoch)1014     void NitrokeyManager::send_startup(uint64_t seconds_from_epoch){
1015       auto p = get_payload<stick20::SendStartup>();
1016 //      p.set_defaults(); //set current time
1017       p.localtime = seconds_from_epoch;
1018       stick20::SendStartup::CommandTransaction::run(device, p);
1019     }
1020 
unlock_encrypted_volume(const char * user_pin)1021     void NitrokeyManager::unlock_encrypted_volume(const char* user_pin){
1022       misc::execute_password_command<stick20::EnableEncryptedPartition>(device, user_pin);
1023     }
1024 
unlock_hidden_volume(const char * hidden_volume_password)1025     void NitrokeyManager::unlock_hidden_volume(const char* hidden_volume_password) {
1026       misc::execute_password_command<stick20::EnableHiddenEncryptedPartition>(device, hidden_volume_password);
1027     }
1028 
set_encrypted_volume_read_only(const char * admin_pin)1029     void NitrokeyManager::set_encrypted_volume_read_only(const char* admin_pin) {
1030         misc::execute_password_command<stick20::SetEncryptedVolumeReadOnly>(device, admin_pin);
1031     }
1032 
set_encrypted_volume_read_write(const char * admin_pin)1033     void NitrokeyManager::set_encrypted_volume_read_write(const char* admin_pin) {
1034         misc::execute_password_command<stick20::SetEncryptedVolumeReadWrite>(device, admin_pin);
1035     }
1036 
1037     //TODO check is encrypted volume unlocked before execution
1038     //if not return library exception
create_hidden_volume(uint8_t slot_nr,uint8_t start_percent,uint8_t end_percent,const char * hidden_volume_password)1039     void NitrokeyManager::create_hidden_volume(uint8_t slot_nr, uint8_t start_percent, uint8_t end_percent,
1040                                                const char *hidden_volume_password) {
1041       auto p = get_payload<stick20::SetupHiddenVolume>();
1042       p.SlotNr_u8 = slot_nr;
1043       p.StartBlockPercent_u8 = start_percent;
1044       p.EndBlockPercent_u8 = end_percent;
1045       strcpyT(p.HiddenVolumePassword_au8, hidden_volume_password);
1046       stick20::SetupHiddenVolume::CommandTransaction::run(device, p);
1047     }
1048 
set_unencrypted_read_only_admin(const char * admin_pin)1049     void NitrokeyManager::set_unencrypted_read_only_admin(const char* admin_pin) {
1050       //from v0.49, v0.52+ it needs Admin PIN
1051       if (set_unencrypted_volume_rorw_pin_type_user()){
1052         LOG("set_unencrypted_read_only_admin is not supported for this version of Storage device. "
1053                 "Please update firmware to v0.52+. Doing nothing.", nitrokey::log::Loglevel::WARNING);
1054         return;
1055       }
1056       misc::execute_password_command<stick20::SetUnencryptedVolumeReadOnlyAdmin>(device, admin_pin);
1057     }
1058 
set_unencrypted_read_only(const char * user_pin)1059     void NitrokeyManager::set_unencrypted_read_only(const char *user_pin) {
1060         //until v0.48 (incl. v0.50 and v0.51) User PIN was sufficient
1061         LOG("set_unencrypted_read_only is deprecated. Use set_unencrypted_read_only_admin instead.",
1062             nitrokey::log::Loglevel::WARNING);
1063       if (!set_unencrypted_volume_rorw_pin_type_user()){
1064         LOG("set_unencrypted_read_only is not supported for this version of Storage device. Doing nothing.",
1065             nitrokey::log::Loglevel::WARNING);
1066         return;
1067       }
1068       misc::execute_password_command<stick20::SendSetReadonlyToUncryptedVolume>(device, user_pin);
1069     }
1070 
set_unencrypted_read_write_admin(const char * admin_pin)1071     void NitrokeyManager::set_unencrypted_read_write_admin(const char* admin_pin) {
1072       //from v0.49, v0.52+ it needs Admin PIN
1073       if (set_unencrypted_volume_rorw_pin_type_user()){
1074         LOG("set_unencrypted_read_write_admin is not supported for this version of Storage device. "
1075                 "Please update firmware to v0.52+. Doing nothing.", nitrokey::log::Loglevel::WARNING);
1076         return;
1077       }
1078       misc::execute_password_command<stick20::SetUnencryptedVolumeReadWriteAdmin>(device, admin_pin);
1079     }
1080 
set_unencrypted_read_write(const char * user_pin)1081     void NitrokeyManager::set_unencrypted_read_write(const char *user_pin) {
1082         //until v0.48 (incl. v0.50 and v0.51) User PIN was sufficient
1083       LOG("set_unencrypted_read_write is deprecated. Use set_unencrypted_read_write_admin instead.",
1084           nitrokey::log::Loglevel::WARNING);
1085       if (!set_unencrypted_volume_rorw_pin_type_user()){
1086         LOG("set_unencrypted_read_write is not supported for this version of Storage device. Doing nothing.",
1087             nitrokey::log::Loglevel::WARNING);
1088         return;
1089       }
1090       misc::execute_password_command<stick20::SendSetReadwriteToUncryptedVolume>(device, user_pin);
1091     }
1092 
set_unencrypted_volume_rorw_pin_type_user()1093     bool NitrokeyManager::set_unencrypted_volume_rorw_pin_type_user(){
1094       auto minor_firmware_version = get_minor_firmware_version();
1095       return minor_firmware_version <= 48 || minor_firmware_version == 50 || minor_firmware_version == 51;
1096     }
1097 
export_firmware(const char * admin_pin)1098   void NitrokeyManager::export_firmware(const char* admin_pin) {
1099       misc::execute_password_command<stick20::ExportFirmware>(device, admin_pin);
1100     }
1101 
enable_firmware_update(const char * firmware_pin)1102     void NitrokeyManager::enable_firmware_update(const char* firmware_pin) {
1103       misc::execute_password_command<stick20::EnableFirmwareUpdate>(device, firmware_pin);
1104     }
1105 
clear_new_sd_card_warning(const char * admin_pin)1106     void NitrokeyManager::clear_new_sd_card_warning(const char* admin_pin) {
1107       misc::execute_password_command<stick20::SendClearNewSdCardFound>(device, admin_pin);
1108     }
1109 
fill_SD_card_with_random_data(const char * admin_pin)1110     void NitrokeyManager::fill_SD_card_with_random_data(const char* admin_pin) {
1111       auto p = get_payload<stick20::FillSDCardWithRandomChars>();
1112       p.set_defaults();
1113       strcpyT(p.admin_pin, admin_pin);
1114       stick20::FillSDCardWithRandomChars::CommandTransaction::run(device, p);
1115     }
1116 
change_update_password(const char * current_update_password,const char * new_update_password)1117     void NitrokeyManager::change_update_password(const char* current_update_password, const char* new_update_password) {
1118       auto p = get_payload<stick20::ChangeUpdatePassword>();
1119       strcpyT(p.current_update_password, current_update_password);
1120       strcpyT(p.new_update_password, new_update_password);
1121       stick20::ChangeUpdatePassword::CommandTransaction::run(device, p);
1122     }
1123 
get_status_storage_as_string()1124     char * NitrokeyManager::get_status_storage_as_string(){
1125       auto p = stick20::GetDeviceStatus::CommandTransaction::run(device);
1126       return strndup(p.data().dissect().c_str(), max_string_field_length);
1127     }
1128 
get_status_storage()1129     stick20::DeviceConfigurationResponsePacket::ResponsePayload NitrokeyManager::get_status_storage(){
1130       auto p = stick20::GetDeviceStatus::CommandTransaction::run(device);
1131       return p.data();
1132     }
1133 
get_SD_usage_data_as_string()1134     char * NitrokeyManager::get_SD_usage_data_as_string(){
1135       auto p = stick20::GetSDCardOccupancy::CommandTransaction::run(device);
1136       return strndup(p.data().dissect().c_str(), max_string_field_length);
1137     }
1138 
get_SD_usage_data()1139     std::pair<uint8_t,uint8_t> NitrokeyManager::get_SD_usage_data(){
1140       auto p = stick20::GetSDCardOccupancy::CommandTransaction::run(device);
1141       return std::make_pair(p.data().WriteLevelMin, p.data().WriteLevelMax);
1142     }
1143 
get_progress_bar_value()1144     int NitrokeyManager::get_progress_bar_value(){
1145       try{
1146         stick20::GetDeviceStatus::CommandTransaction::run(device);
1147         return -1;
1148       }
1149       catch (LongOperationInProgressException &e){
1150         return e.progress_bar_value;
1151       }
1152     }
1153 
get_TOTP_code(uint8_t slot_number,const char * user_temporary_password)1154   string NitrokeyManager::get_TOTP_code(uint8_t slot_number, const char *user_temporary_password) {
1155     return get_TOTP_code(slot_number, 0, 0, 0, user_temporary_password);
1156   }
1157 
1158   /**
1159    * Returns ReadSlot structure, describing OTP slot configuration. Always return binary counter -
1160    * does the necessary conversion, if needed, to unify the behavior across Pro and Storage.
1161    * @private For internal use only
1162    * @param slot_number which OTP slot to use (usual format)
1163    * @return ReadSlot structure
1164    */
get_OTP_slot_data(const uint8_t slot_number)1165   stick10::ReadSlot::ResponsePayload NitrokeyManager::get_OTP_slot_data(const uint8_t slot_number) {
1166     auto p = get_payload<stick10::ReadSlot>();
1167     p.slot_number = slot_number;
1168     p.data_format = stick10::ReadSlot::CounterFormat::BINARY; // ignored for devices other than Storage v0.54+
1169     auto data = stick10::ReadSlot::CommandTransaction::run(device, p);
1170 
1171     auto &payload = data.data();
1172 
1173     // if fw <=v0.53 and asked binary - do the conversion from ASCII
1174     if (device->get_device_model() == DeviceModel::STORAGE && get_minor_firmware_version() <= 53
1175          && is_internal_hotp_slot_number(slot_number))
1176     {
1177       //convert counter from string to ull
1178       auto counter_s = std::string(payload.slot_counter_s, payload.slot_counter_s + sizeof(payload.slot_counter_s));
1179       payload.slot_counter = std::stoull(counter_s);
1180     }
1181 
1182     return payload;
1183   }
1184 
get_TOTP_slot_data(const uint8_t slot_number)1185   stick10::ReadSlot::ResponsePayload NitrokeyManager::get_TOTP_slot_data(const uint8_t slot_number) {
1186     return get_OTP_slot_data(get_internal_slot_number_for_totp(slot_number));
1187   }
1188 
get_HOTP_slot_data(const uint8_t slot_number)1189   stick10::ReadSlot::ResponsePayload NitrokeyManager::get_HOTP_slot_data(const uint8_t slot_number) {
1190     return get_OTP_slot_data(get_internal_slot_number_for_hotp(slot_number));
1191   }
1192 
lock_encrypted_volume()1193   void NitrokeyManager::lock_encrypted_volume() {
1194     misc::execute_password_command<stick20::DisableEncryptedPartition>(device, "");
1195   }
1196 
lock_hidden_volume()1197   void NitrokeyManager::lock_hidden_volume() {
1198     misc::execute_password_command<stick20::DisableHiddenEncryptedPartition>(device, "");
1199   }
1200 
get_SD_card_size()1201   uint8_t NitrokeyManager::get_SD_card_size() {
1202     auto data = stick20::ProductionTest::CommandTransaction::run(device);
1203     return data.data().SD_Card_Size_u8;
1204   }
1205 
get_current_device_id() const1206     const string NitrokeyManager::get_current_device_id() const {
1207         return current_device_id;
1208     }
1209 
wink()1210   void NitrokeyManager::wink(){
1211     stick20::Wink::CommandTransaction::run(device);
1212   };
1213 
production_info()1214   stick20::ProductionTest::ResponsePayload NitrokeyManager::production_info(){
1215     auto data = stick20::ProductionTest::CommandTransaction::run(device);
1216     return data.data();
1217   };
1218 
enable_firmware_update_pro(const char * firmware_pin)1219   void NitrokeyManager::enable_firmware_update_pro(const char *firmware_pin) {
1220     auto p = get_payload<FirmwareUpdate>();
1221     strcpyT(p.firmware_password, firmware_pin);
1222     FirmwareUpdate::CommandTransaction::run(device, p);
1223   }
1224 
1225   void
change_firmware_update_password_pro(const char * firmware_pin_current,const char * firmware_pin_new)1226   NitrokeyManager::change_firmware_update_password_pro(const char *firmware_pin_current, const char *firmware_pin_new) {
1227     auto p = get_payload<FirmwarePasswordChange>();
1228     strcpyT(p.firmware_password_current, firmware_pin_current);
1229     strcpyT(p.firmware_password_new, firmware_pin_new);
1230     FirmwarePasswordChange::CommandTransaction::run(device, p);
1231   }
1232 
1233 }
1234