diff options
| author | Szczepan Zalega <szczepan@nitrokey.com> | 2020-07-28 12:50:53 +0200 | 
|---|---|---|
| committer | Szczepan Zalega <szczepan@nitrokey.com> | 2020-07-28 12:50:53 +0200 | 
| commit | a36392dd83def4397d100addf57870ebea5de0e9 (patch) | |
| tree | 41aaefa5b44ffc3b879f490c58e008930d5f4fbd | |
| parent | dc1cfa6252073ac345412e7df9c5cc0365bb7f11 (diff) | |
| download | libnitrokey-a36392dd83def4397d100addf57870ebea5de0e9.tar.gz libnitrokey-a36392dd83def4397d100addf57870ebea5de0e9.tar.bz2 | |
Extract OTP features to separate unit
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | NK_C_API.cc | 2 | ||||
| -rw-r--r-- | NitrokeyManager.cc | 371 | ||||
| -rw-r--r-- | NitrokeyManagerOTP.cc | 327 | ||||
| -rw-r--r-- | NitrokeyManagerOTP.h | 6 | ||||
| -rw-r--r-- | NitrokeyManagerStorage.cpp | 1 | ||||
| -rw-r--r-- | libnitrokey/NitrokeyManager.h | 1 | 
7 files changed, 345 insertions, 365 deletions
| diff --git a/CMakeLists.txt b/CMakeLists.txt index 6793ac9..6e0bcb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,8 @@ set(SOURCE_FILES      NitrokeyManager.cc      NitrokeyManagerStorage.cpp      NitrokeyManagerStorage.h +    NitrokeyManagerOTP.cc +    NitrokeyManagerOTP.h      NK_C_API.h      NK_C_API.cc      NK_C_API_helpers.h diff --git a/NK_C_API.cc b/NK_C_API.cc index 2f5a0cc..9dd0837 100644 --- a/NK_C_API.cc +++ b/NK_C_API.cc @@ -37,9 +37,9 @@ using namespace nitrokey;  const uint8_t NK_PWS_SLOT_COUNT = PWS_SLOT_COUNT;  uint8_t NK_last_command_status = 0; -static const int max_string_field_length = 100;  #include "NK_C_API_helpers.h" +#include "NitrokeyManagerOTP.h"  #ifdef __cplusplus  extern "C" { diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index 3e0b5f6..cde559b 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -19,25 +19,23 @@   * SPDX-License-Identifier: LGPL-3.0   */ -#include <cstring> -#include <iostream>  #include "libnitrokey/NitrokeyManager.h" +#include "NitrokeyManagerOTP.h"  #include "libnitrokey/LibraryException.h" -#include <algorithm> -#include <unordered_map> -#include <stick20_commands.h> -#include "libnitrokey/misc.h" -#include <mutex>  #include "libnitrokey/cxx_semantics.h"  #include "libnitrokey/misc.h" +#include <algorithm> +#include <cstring>  #include <functional> +#include <iostream> +#include <mutex>  #include <stick10_commands.h> +#include <stick20_commands.h> +#include <unordered_map>  std::mutex nitrokey::proto::send_receive_mtx;  namespace nitrokey{ -constexpr int max_string_field_length = 2*1024; //storage's status string is ~1k -      std::mutex mex_dev_com_manager;  using nitrokey::misc::strcpyT; @@ -420,265 +418,7 @@ using nitrokey::misc::strcpyT;          return response.data().dissect();      } -    string getFilledOTPCode(uint32_t code, bool use_8_digits){ -      stringstream s; -      s << std::right << std::setw(use_8_digits ? 8 : 6) << std::setfill('0') << code; -      return s.str(); -    } - -    string NitrokeyManager::get_HOTP_code(uint8_t slot_number, const char *user_temporary_password) { -      if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - -      if (is_authorization_command_supported()){ -        auto gh = get_payload<GetHOTP>(); -        gh.slot_number = get_internal_slot_number_for_hotp(slot_number); -        if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0){ //FIXME use string instead of strlen -            authorize_packet<GetHOTP, UserAuthorize>(gh, user_temporary_password, device); -        } -        auto resp = GetHOTP::CommandTransaction::run(device, gh); -        return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); -      } else { -        auto gh = get_payload<stick10_08::GetHOTP>(); -        gh.slot_number = get_internal_slot_number_for_hotp(slot_number); -        if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0) { -          strcpyT(gh.temporary_user_password, user_temporary_password); -        } -        auto resp = stick10_08::GetHOTP::CommandTransaction::run(device, gh); -        return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); -      } -      return ""; -    } - -    bool NitrokeyManager::is_internal_hotp_slot_number(uint8_t slot_number) const { return slot_number < 0x20; } -    bool NitrokeyManager::is_valid_hotp_slot_number(uint8_t slot_number) const { return slot_number < 3; } -    bool NitrokeyManager::is_valid_totp_slot_number(uint8_t slot_number) const { return slot_number < 0x10-1; } //15 -    uint8_t NitrokeyManager::get_internal_slot_number_for_totp(uint8_t slot_number) const { return (uint8_t) (0x20 + slot_number); } -    uint8_t NitrokeyManager::get_internal_slot_number_for_hotp(uint8_t slot_number) const { return (uint8_t) (0x10 + slot_number); } - - - -    string NitrokeyManager::get_TOTP_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, -                                          uint8_t last_interval, -                                          const char *user_temporary_password) { -        if(!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); -        slot_number = get_internal_slot_number_for_totp(slot_number); - -        if (is_authorization_command_supported()){ -          auto gt = get_payload<GetTOTP>(); -          gt.slot_number = slot_number; -          gt.challenge = challenge; -          gt.last_interval = last_interval; -          gt.last_totp_time = last_totp_time; - -          if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0){ //FIXME use string instead of strlen -              authorize_packet<GetTOTP, UserAuthorize>(gt, user_temporary_password, device); -          } -          auto resp = GetTOTP::CommandTransaction::run(device, gt); -          return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); -        } else { -          auto gt = get_payload<stick10_08::GetTOTP>(); -          strcpyT(gt.temporary_user_password, user_temporary_password); -          gt.slot_number = slot_number; -          auto resp = stick10_08::GetTOTP::CommandTransaction::run(device, gt); -          return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); -        } -      return ""; -    } - -    bool NitrokeyManager::erase_slot(uint8_t slot_number, const char *temporary_password) { -      if (is_authorization_command_supported()){ -        auto p = get_payload<EraseSlot>(); -        p.slot_number = slot_number; -        authorize_packet<EraseSlot, Authorize>(p, temporary_password, device); -        auto resp = EraseSlot::CommandTransaction::run(device,p); -      } else { -        auto p = get_payload<stick10_08::EraseSlot>(); -        p.slot_number = slot_number; -        strcpyT(p.temporary_admin_password, temporary_password); -        auto resp = stick10_08::EraseSlot::CommandTransaction::run(device,p); -      } -        return true; -    } - -    bool NitrokeyManager::erase_hotp_slot(uint8_t slot_number, const char *temporary_password) { -        if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); -        slot_number = get_internal_slot_number_for_hotp(slot_number); -        return erase_slot(slot_number, temporary_password); -    } - -    bool NitrokeyManager::erase_totp_slot(uint8_t slot_number, const char *temporary_password) { -        if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); -        slot_number = get_internal_slot_number_for_totp(slot_number); -        return erase_slot(slot_number, temporary_password); -    } - -    template <typename T, typename U> -    void vector_copy_ranged(T& dest, std::vector<U> &vec, size_t begin, size_t elements_to_copy){ -        const size_t d_size = sizeof(dest); -      if(d_size < elements_to_copy){ -            throw TargetBufferSmallerThanSource(elements_to_copy, d_size); -        } -        std::fill(dest, dest+d_size, 0); -        std::copy(vec.begin() + begin, vec.begin() +begin + elements_to_copy, dest); -    } - -    template <typename T, typename U> -    void vector_copy(T& dest, std::vector<U> &vec){ -        const size_t d_size = sizeof(dest); -        if(d_size < vec.size()){ -            throw TargetBufferSmallerThanSource(vec.size(), d_size); -        } -        std::fill(dest, dest+d_size, 0); -        std::copy(vec.begin(), vec.end(), dest); -    } - -    bool NitrokeyManager::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) { -        if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - -      int internal_slot_number = get_internal_slot_number_for_hotp(slot_number); -      if (is_authorization_command_supported()){ -        write_HOTP_slot_authorize(internal_slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, -                    token_ID, temporary_password); -      } else { -        write_OTP_slot_no_authorize(internal_slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, -                                    token_ID, temporary_password); -      } -      return true; -    } - -    void NitrokeyManager::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) { -      auto payload = get_payload<WriteToHOTPSlot>(); -      payload.slot_number = slot_number; -      auto secret_bin = misc::hex_string_to_byte(secret); -      vector_copy(payload.slot_secret, secret_bin); -      strcpyT(payload.slot_name, slot_name); -      strcpyT(payload.slot_token_id, token_ID); -      switch (device->get_device_model() ){ -        case DeviceModel::LIBREM: -        case DeviceModel::PRO: { -          payload.slot_counter = hotp_counter; -          break; -        } -        case DeviceModel::STORAGE: { -          string counter = to_string(hotp_counter); -          strcpyT(payload.slot_counter_s, counter.c_str()); -          break; -        } -        default: -          LOG(string(__FILE__) + to_string(__LINE__) + -                          string(__FUNCTION__) + string(" Unhandled device model for HOTP") -              , Loglevel::DEBUG); -          break; -      } -      payload.use_8_digits = use_8_digits; -      payload.use_enter = use_enter; -      payload.use_tokenID = use_tokenID; - -      authorize_packet<WriteToHOTPSlot, Authorize>(payload, temporary_password, device); - -      auto resp = WriteToHOTPSlot::CommandTransaction::run(device, payload); -    } - -    bool NitrokeyManager::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) { -        if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); -       int internal_slot_number = get_internal_slot_number_for_totp(slot_number); - -      if (is_authorization_command_supported()){ -      write_TOTP_slot_authorize(internal_slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, -                                token_ID, temporary_password); -      } else { -        write_OTP_slot_no_authorize(internal_slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, -                                    token_ID, temporary_password); -      } - -      return true; -    } - -    void NitrokeyManager::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) const { - -      auto payload2 = get_payload<stick10_08::SendOTPData>(); -      strcpyT(payload2.temporary_admin_password, temporary_password); -      strcpyT(payload2.data, slot_name); -      payload2.setTypeName(); -      stick10_08::SendOTPData::CommandTransaction::run(device, payload2); - -      payload2.setTypeSecret(); -      payload2.id = 0; -      auto secret_bin = misc::hex_string_to_byte(secret); -      auto remaining_secret_length = secret_bin.size(); -      const auto maximum_OTP_secret_size = 40; -      if(remaining_secret_length > maximum_OTP_secret_size){ -        throw TargetBufferSmallerThanSource(remaining_secret_length, maximum_OTP_secret_size); -      } - -      while (remaining_secret_length>0){ -        const auto bytesToCopy = std::min(sizeof(payload2.data), remaining_secret_length); -        const auto start = secret_bin.size() - remaining_secret_length; -        memset(payload2.data, 0, sizeof(payload2.data)); -        vector_copy_ranged(payload2.data, secret_bin, start, bytesToCopy); -        stick10_08::SendOTPData::CommandTransaction::run(device, payload2); -        remaining_secret_length -= bytesToCopy; -        payload2.id++; -      } - -      auto payload = get_payload<stick10_08::WriteToOTPSlot>(); -      strcpyT(payload.temporary_admin_password, temporary_password); -      strcpyT(payload.slot_token_id, token_ID); -      payload.use_8_digits = use_8_digits; -      payload.use_enter = use_enter; -      payload.use_tokenID = use_tokenID; -      payload.slot_counter_or_interval = counter_or_interval; -      payload.slot_number = internal_slot_number; -      stick10_08::WriteToOTPSlot::CommandTransaction::run(device, payload); -    } - -    void NitrokeyManager::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) { -      auto payload = get_payload<WriteToTOTPSlot>(); -      payload.slot_number = slot_number; -      auto secret_bin = misc::hex_string_to_byte(secret); -      vector_copy(payload.slot_secret, secret_bin); -      strcpyT(payload.slot_name, slot_name); -      strcpyT(payload.slot_token_id, token_ID); -      payload.slot_interval = time_window; //FIXME naming -      payload.use_8_digits = use_8_digits; -      payload.use_enter = use_enter; -      payload.use_tokenID = use_tokenID; - -      authorize_packet<WriteToTOTPSlot, Authorize>(payload, temporary_password, device); - -      auto resp = WriteToTOTPSlot::CommandTransaction::run(device, payload); -    } - -    char * NitrokeyManager::get_totp_slot_name(uint8_t slot_number) { -        if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); -        slot_number = get_internal_slot_number_for_totp(slot_number); -        return get_slot_name(slot_number); -    } -    char * NitrokeyManager::get_hotp_slot_name(uint8_t slot_number) { -        if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); -        slot_number = get_internal_slot_number_for_hotp(slot_number); -        return get_slot_name(slot_number); -    } - - -  char * NitrokeyManager::get_slot_name(uint8_t slot_number)  { -        auto payload = get_payload<GetSlotName>(); -        payload.slot_number = slot_number; -        auto resp = GetSlotName::CommandTransaction::run(device, payload); -        return strndup((const char *) resp.data().slot_name, max_string_field_length); -    } +    // 15      bool NitrokeyManager::first_authenticate(const char *pin, const char *temporary_password) {          auto authreq = get_payload<FirstAuthenticate>(); @@ -688,26 +428,6 @@ using nitrokey::misc::strcpyT;          return true;      } -    bool NitrokeyManager::set_time(uint64_t time) { -        auto p = get_payload<SetTime>(); -        p.reset = 1; -        p.time = time; -        SetTime::CommandTransaction::run(device, p); -        return false; -    } - -    void NitrokeyManager::set_time_soft(uint64_t time) { -        auto p = get_payload<SetTime>(); -        p.reset = 0; -        p.time = time; -        SetTime::CommandTransaction::run(device, p); -    } - -    bool NitrokeyManager::get_time(uint64_t time) { -        set_time_soft(time); -        return true; -    } -      void NitrokeyManager::change_user_PIN(const char *current_PIN, const char *new_PIN) {          change_PIN_general<ChangeUserPin, PasswordKind::User>(current_PIN, new_PIN);      } @@ -888,30 +608,6 @@ using nitrokey::misc::strcpyT;        }      } - -    void NitrokeyManager::write_config(uint8_t numlock, uint8_t capslock, uint8_t scrolllock, bool enable_user_password, -                                       bool delete_user_password, const char *admin_temporary_password) { -        auto p = get_payload<stick10_08::WriteGeneralConfig>(); -        p.numlock = numlock; -        p.capslock = capslock; -        p.scrolllock = scrolllock; -        p.enable_user_password = static_cast<uint8_t>(enable_user_password ? 1 : 0); -        p.delete_user_password = static_cast<uint8_t>(delete_user_password ? 1 : 0); -        if (is_authorization_command_supported()){ -          authorize_packet<stick10_08::WriteGeneralConfig, Authorize>(p, admin_temporary_password, device); -        } else { -          strcpyT(p.temporary_admin_password, admin_temporary_password); -        } -        stick10_08::WriteGeneralConfig::CommandTransaction::run(device, p); -    } - -    vector<uint8_t> NitrokeyManager::read_config() { -        auto responsePayload = GetStatus::CommandTransaction::run(device); -        vector<uint8_t> v = vector<uint8_t>(responsePayload.data().general_config, -                                            responsePayload.data().general_config+sizeof(responsePayload.data().general_config)); -        return v; -    } -      bool NitrokeyManager::is_authorization_command_supported(){        //authorization command is supported for versions equal or below:          auto m = std::unordered_map<DeviceModel , int, EnumClassHash>({ @@ -922,16 +618,6 @@ using nitrokey::misc::strcpyT;          return get_minor_firmware_version() <= m[device->get_device_model()];      } -    bool NitrokeyManager::is_320_OTP_secret_supported(){ -        // 320 bit OTP secret is supported by version bigger or equal to: -        auto m = std::unordered_map<DeviceModel , int, EnumClassHash>({ -                                               {DeviceModel::PRO, 8}, -                                               {DeviceModel::LIBREM, 8}, -                                               {DeviceModel::STORAGE, 54}, -         }); -        return get_minor_firmware_version() >= m[device->get_device_model()]; -    } -      DeviceModel NitrokeyManager::get_connected_device_model() const{          if (device == nullptr){              throw DeviceNotConnected("device not connected"); @@ -988,47 +674,6 @@ using nitrokey::misc::strcpyT;          return true;      } - -  string NitrokeyManager::get_TOTP_code(uint8_t slot_number, const char *user_temporary_password) { -    return get_TOTP_code(slot_number, 0, 0, 0, user_temporary_password); -  } - -  /** -   * Returns ReadSlot structure, describing OTP slot configuration. Always return binary counter - -   * does the necessary conversion, if needed, to unify the behavior across Pro and Storage. -   * @private For internal use only -   * @param slot_number which OTP slot to use (usual format) -   * @return ReadSlot structure -   */ -  stick10::ReadSlot::ResponsePayload NitrokeyManager::get_OTP_slot_data(const uint8_t slot_number) { -    auto p = get_payload<stick10::ReadSlot>(); -    p.slot_number = slot_number; -    p.data_format = stick10::ReadSlot::CounterFormat::BINARY; // ignored for devices other than Storage v0.54+ -    auto data = stick10::ReadSlot::CommandTransaction::run(device, p); - -    auto &payload = data.data(); - -    // if fw <=v0.53 and asked binary - do the conversion from ASCII -    if (device->get_device_model() == DeviceModel::STORAGE && get_minor_firmware_version() <= 53 -         && is_internal_hotp_slot_number(slot_number)) -    { -      //convert counter from string to ull -      auto counter_s = std::string(payload.slot_counter_s, payload.slot_counter_s + sizeof(payload.slot_counter_s)); -      payload.slot_counter = std::stoull(counter_s); -    } - -    return payload; -  } - -  stick10::ReadSlot::ResponsePayload NitrokeyManager::get_TOTP_slot_data(const uint8_t slot_number) { -    return get_OTP_slot_data(get_internal_slot_number_for_totp(slot_number)); -  } - -  stick10::ReadSlot::ResponsePayload NitrokeyManager::get_HOTP_slot_data(const uint8_t slot_number) { -    return get_OTP_slot_data(get_internal_slot_number_for_hotp(slot_number)); -  } - -      const string NitrokeyManager::get_current_device_id() const {          return current_device_id;      } diff --git a/NitrokeyManagerOTP.cc b/NitrokeyManagerOTP.cc new file mode 100644 index 0000000..93f2188 --- /dev/null +++ b/NitrokeyManagerOTP.cc @@ -0,0 +1,327 @@ +#include "NitrokeyManagerOTP.h" +using nitrokey::misc::strcpyT; + +std::string getFilledOTPCode(uint32_t code, bool use_8_digits){ +  std::stringstream s; +  s << std::right << std::setw(use_8_digits ? 8 : 6) << std::setfill('0') << code; +  return s.str(); +} +std::string nitrokey::NitrokeyManager::get_HOTP_code(uint8_t slot_number, const char *user_temporary_password) { +  if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); + +  if (is_authorization_command_supported()){ +    auto gh = get_payload<GetHOTP>(); +    gh.slot_number = get_internal_slot_number_for_hotp(slot_number); +    if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0){ //FIXME use string instead of strlen +        authorize_packet<GetHOTP, UserAuthorize>(gh, user_temporary_password, device); +    } +    auto resp = GetHOTP::CommandTransaction::run(device, gh); +    return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); +  } else { +    auto gh = get_payload<stick10_08::GetHOTP>(); +    gh.slot_number = get_internal_slot_number_for_hotp(slot_number); +    if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0) { +      strcpyT(gh.temporary_user_password, user_temporary_password); +    } +    auto resp = stick10_08::GetHOTP::CommandTransaction::run(device, gh); +    return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); +  } +  return ""; +} +bool nitrokey::NitrokeyManager::is_internal_hotp_slot_number(uint8_t slot_number) const { return slot_number < 0x20; } +bool nitrokey::NitrokeyManager::is_valid_hotp_slot_number(uint8_t slot_number) const { return slot_number < 3; } +bool nitrokey::NitrokeyManager::is_valid_totp_slot_number(uint8_t slot_number) const { return slot_number < 0x10-1; } +uint8_t nitrokey::NitrokeyManager::get_internal_slot_number_for_totp(uint8_t slot_number) const { return (uint8_t) (0x20 + slot_number); +} +uint8_t nitrokey::NitrokeyManager::get_internal_slot_number_for_hotp(uint8_t slot_number) const { return (uint8_t) (0x10 + slot_number); } +std::string nitrokey::NitrokeyManager::get_TOTP_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, +                                      uint8_t last_interval, +                                      const char *user_temporary_password) { +    if(!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); +    slot_number = get_internal_slot_number_for_totp(slot_number); + +    if (is_authorization_command_supported()){ +      auto gt = get_payload<GetTOTP>(); +      gt.slot_number = slot_number; +      gt.challenge = challenge; +      gt.last_interval = last_interval; +      gt.last_totp_time = last_totp_time; + +      if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0){ //FIXME use string instead of strlen +          authorize_packet<GetTOTP, UserAuthorize>(gt, user_temporary_password, device); +      } +      auto resp = GetTOTP::CommandTransaction::run(device, gt); +      return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); +    } else { +      auto gt = get_payload<stick10_08::GetTOTP>(); +      strcpyT(gt.temporary_user_password, user_temporary_password); +      gt.slot_number = slot_number; +      auto resp = stick10_08::GetTOTP::CommandTransaction::run(device, gt); +      return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); +    } +  return ""; +} +bool nitrokey::NitrokeyManager::erase_slot(uint8_t slot_number, const char *temporary_password) { +  if (is_authorization_command_supported()){ +    auto p = get_payload<EraseSlot>(); +    p.slot_number = slot_number; +    authorize_packet<EraseSlot, Authorize>(p, temporary_password, device); +    auto resp = EraseSlot::CommandTransaction::run(device,p); +  } else { +    auto p = get_payload<stick10_08::EraseSlot>(); +    p.slot_number = slot_number; +    strcpyT(p.temporary_admin_password, temporary_password); +    auto resp = stick10_08::EraseSlot::CommandTransaction::run(device,p); +  } +    return true; +} +bool nitrokey::NitrokeyManager::erase_hotp_slot(uint8_t slot_number, const char *temporary_password) { +    if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); +    slot_number = get_internal_slot_number_for_hotp(slot_number); +    return erase_slot(slot_number, temporary_password); +} +bool nitrokey::NitrokeyManager::erase_totp_slot(uint8_t slot_number, const char *temporary_password) { +    if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); +    slot_number = get_internal_slot_number_for_totp(slot_number); +    return erase_slot(slot_number, temporary_password); +} +template <typename T, typename U> +void vector_copy_ranged(T& dest, std::vector<U> &vec, std::size_t begin, std::size_t elements_to_copy){ +    const std::size_t d_size = sizeof(dest); +  if(d_size < elements_to_copy){ +      throw TargetBufferSmallerThanSource(elements_to_copy, d_size); +    } +    std::fill(dest, dest+d_size, 0); +    std::copy(vec.begin() + begin, vec.begin() +begin + elements_to_copy, dest); +} +template <typename T, typename U> +void vector_copy(T& dest, std::vector<U> &vec){ +    const std::size_t d_size = sizeof(dest); +    if(d_size < vec.size()){ +        throw TargetBufferSmallerThanSource(vec.size(), d_size); +    } +    std::fill(dest, dest+d_size, 0); +    std::copy(vec.begin(), vec.end(), dest); +} +bool nitrokey::NitrokeyManager::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) { +    if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); + +  int internal_slot_number = get_internal_slot_number_for_hotp(slot_number); +  if (is_authorization_command_supported()){ +    write_HOTP_slot_authorize(internal_slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, +                token_ID, temporary_password); +  } else { +    write_OTP_slot_no_authorize(internal_slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, +                                token_ID, temporary_password); +  } +  return true; +} +void nitrokey::NitrokeyManager::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) { +  auto payload = get_payload<WriteToHOTPSlot>(); +  payload.slot_number = slot_number; +  auto secret_bin = misc::hex_string_to_byte(secret); +  vector_copy(payload.slot_secret, secret_bin); +  strcpyT(payload.slot_name, slot_name); +  strcpyT(payload.slot_token_id, token_ID); +  switch (device->get_device_model() ){ +    case DeviceModel::LIBREM: +    case DeviceModel::PRO: { +      payload.slot_counter = hotp_counter; +      break; +    } +    case DeviceModel::STORAGE: { +      string counter = to_string(hotp_counter); +      strcpyT(payload.slot_counter_s, counter.c_str()); +      break; +    } +    default: +      LOG(string(__FILE__) + to_string(__LINE__) + +                      string(__FUNCTION__) + string(" Unhandled device model for HOTP") +          , Loglevel::DEBUG); +      break; +  } +  payload.use_8_digits = use_8_digits; +  payload.use_enter = use_enter; +  payload.use_tokenID = use_tokenID; + +  authorize_packet<WriteToHOTPSlot, Authorize>(payload, temporary_password, device); + +  auto resp = WriteToHOTPSlot::CommandTransaction::run(device, payload); +} +bool nitrokey::NitrokeyManager::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) { +    if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); +    int internal_slot_number = get_internal_slot_number_for_totp(slot_number); + +  if (is_authorization_command_supported()){ +  write_TOTP_slot_authorize(internal_slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, +                            token_ID, temporary_password); +  } else { +    write_OTP_slot_no_authorize(internal_slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, +                                token_ID, temporary_password); +  } + +  return true; +} +void nitrokey::NitrokeyManager::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) const { + +  auto payload2 = get_payload<stick10_08::SendOTPData>(); +  strcpyT(payload2.temporary_admin_password, temporary_password); +  strcpyT(payload2.data, slot_name); +  payload2.setTypeName(); +  stick10_08::SendOTPData::CommandTransaction::run(device, payload2); + +  payload2.setTypeSecret(); +  payload2.id = 0; +  auto secret_bin = misc::hex_string_to_byte(secret); +  auto remaining_secret_length = secret_bin.size(); +  const auto maximum_OTP_secret_size = 40; +  if(remaining_secret_length > maximum_OTP_secret_size){ +    throw TargetBufferSmallerThanSource(remaining_secret_length, maximum_OTP_secret_size); +  } + +  while (remaining_secret_length>0){ +    const auto bytesToCopy = std::min(sizeof(payload2.data), remaining_secret_length); +    const auto start = secret_bin.size() - remaining_secret_length; +    memset(payload2.data, 0, sizeof(payload2.data)); +    vector_copy_ranged(payload2.data, secret_bin, start, bytesToCopy); +    stick10_08::SendOTPData::CommandTransaction::run(device, payload2); +    remaining_secret_length -= bytesToCopy; +    payload2.id++; +  } + +  auto payload = get_payload<stick10_08::WriteToOTPSlot>(); +  strcpyT(payload.temporary_admin_password, temporary_password); +  strcpyT(payload.slot_token_id, token_ID); +  payload.use_8_digits = use_8_digits; +  payload.use_enter = use_enter; +  payload.use_tokenID = use_tokenID; +  payload.slot_counter_or_interval = counter_or_interval; +  payload.slot_number = internal_slot_number; +  stick10_08::WriteToOTPSlot::CommandTransaction::run(device, payload); +} +void nitrokey::NitrokeyManager::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) { +  auto payload = get_payload<WriteToTOTPSlot>(); +  payload.slot_number = slot_number; +  auto secret_bin = misc::hex_string_to_byte(secret); +  vector_copy(payload.slot_secret, secret_bin); +  strcpyT(payload.slot_name, slot_name); +  strcpyT(payload.slot_token_id, token_ID); +  payload.slot_interval = time_window; //FIXME naming +  payload.use_8_digits = use_8_digits; +  payload.use_enter = use_enter; +  payload.use_tokenID = use_tokenID; + +  authorize_packet<WriteToTOTPSlot, Authorize>(payload, temporary_password, device); + +  auto resp = WriteToTOTPSlot::CommandTransaction::run(device, payload); +} +char * nitrokey::NitrokeyManager::get_totp_slot_name(uint8_t slot_number) { +    if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); +    slot_number = get_internal_slot_number_for_totp(slot_number); +    return get_slot_name(slot_number); +} +char *nitrokey::NitrokeyManager::get_hotp_slot_name(uint8_t slot_number) { +    if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); +    slot_number = get_internal_slot_number_for_hotp(slot_number); +    return get_slot_name(slot_number); +} +char *nitrokey::NitrokeyManager::get_slot_name(uint8_t slot_number)  { +    auto payload = get_payload<GetSlotName>(); +    payload.slot_number = slot_number; +    auto resp = GetSlotName::CommandTransaction::run(device, payload); +    return strndup((const char *) resp.data().slot_name, max_string_field_length); +} +bool nitrokey::NitrokeyManager::set_time(uint64_t time) { +    auto p = get_payload<SetTime>(); +    p.reset = 1; +    p.time = time; +    SetTime::CommandTransaction::run(device, p); +    return false; +} +void nitrokey::NitrokeyManager::set_time_soft(uint64_t time) { +    auto p = get_payload<SetTime>(); +    p.reset = 0; +    p.time = time; +    SetTime::CommandTransaction::run(device, p); +} +bool nitrokey::NitrokeyManager::get_time(uint64_t time) { +    set_time_soft(time); +  return true; +} +void nitrokey::NitrokeyManager::write_config(uint8_t numlock, uint8_t capslock, uint8_t scrolllock, bool enable_user_password, +                                   bool delete_user_password, const char *admin_temporary_password) { +    auto p = get_payload<stick10_08::WriteGeneralConfig>(); +    p.numlock = numlock; +    p.capslock = capslock; +    p.scrolllock = scrolllock; +    p.enable_user_password = static_cast<uint8_t>(enable_user_password ? 1 : 0); +    p.delete_user_password = static_cast<uint8_t>(delete_user_password ? 1 : 0); +    if (is_authorization_command_supported()){ +      authorize_packet<stick10_08::WriteGeneralConfig, Authorize>(p, admin_temporary_password, device); +    } else { +      strcpyT(p.temporary_admin_password, admin_temporary_password); +    } +    stick10_08::WriteGeneralConfig::CommandTransaction::run(device, p); +} +std::vector<uint8_t> nitrokey::NitrokeyManager::read_config() { +    auto responsePayload = GetStatus::CommandTransaction::run(device); +    vector<uint8_t> v = vector<uint8_t>(responsePayload.data().general_config, +                                        responsePayload.data().general_config+sizeof(responsePayload.data().general_config)); +    return v; +} +bool nitrokey::NitrokeyManager::is_320_OTP_secret_supported(){ +  // 320 bit OTP secret is supported by version bigger or equal to: +    auto m = unordered_map<DeviceModel , int, EnumClassHash>({ +                                           {DeviceModel::PRO, 8}, +                                           {DeviceModel::LIBREM, 8}, +                                           {DeviceModel::STORAGE, 54}, +     }); +    return get_minor_firmware_version() >= m[device->get_device_model()]; +} +std::string nitrokey::NitrokeyManager::get_TOTP_code(uint8_t slot_number, const char *user_temporary_password) { +  return get_TOTP_code(slot_number, 0, 0, 0, user_temporary_password); +} /** +   * Returns ReadSlot structure, describing OTP slot configuration. Always +   * return binary counter - does the necessary conversion, if needed, to unify +   * the behavior across Pro and Storage. +   * @private For internal use only +   * @param slot_number which OTP slot to use (usual format) +   * @return ReadSlot structure +   */ +nitrokey::proto::stick10::ReadSlot::ResponsePayload +nitrokey::NitrokeyManager::get_OTP_slot_data(const uint8_t slot_number) { +  auto p = get_payload<ReadSlot>(); +  p.slot_number = slot_number; +  p.data_format = ReadSlot::CounterFormat::BINARY; // ignored for devices other than Storage v0.54+ +  auto data = stick10::ReadSlot::CommandTransaction::run(device, p); + +  auto &payload = data.data(); + +  // if fw <=v0.53 and asked binary - do the conversion from ASCII +  if (device->get_device_model() == DeviceModel::STORAGE && get_minor_firmware_version() <= 53 +       && is_internal_hotp_slot_number(slot_number)) +  { +    //convert counter from string to ull +    auto counter_s = string(payload.slot_counter_s, payload.slot_counter_s + sizeof(payload.slot_counter_s)); +    payload.slot_counter = stoull(counter_s); +  } + +  return payload; +} +  nitrokey::proto::stick10::ReadSlot::ResponsePayload nitrokey::NitrokeyManager::get_TOTP_slot_data(const uint8_t slot_number) { +    return get_OTP_slot_data(get_internal_slot_number_for_totp(slot_number)); +  } +  nitrokey::proto::stick10::ReadSlot::ResponsePayload nitrokey::NitrokeyManager::get_HOTP_slot_data(const uint8_t slot_number) { +    return get_OTP_slot_data(get_internal_slot_number_for_hotp(slot_number)); +  }
\ No newline at end of file diff --git a/NitrokeyManagerOTP.h b/NitrokeyManagerOTP.h new file mode 100644 index 0000000..503fef7 --- /dev/null +++ b/NitrokeyManagerOTP.h @@ -0,0 +1,6 @@ +#ifndef LIBNITROKEY_NITROKEYMANAGEROTP_H +#define LIBNITROKEY_NITROKEYMANAGEROTP_H + +#include "NitrokeyManager.h" + +#endif // LIBNITROKEY_NITROKEYMANAGEROTP_H diff --git a/NitrokeyManagerStorage.cpp b/NitrokeyManagerStorage.cpp index 6f37d88..6814e8b 100644 --- a/NitrokeyManagerStorage.cpp +++ b/NitrokeyManagerStorage.cpp @@ -4,7 +4,6 @@  namespace nitrokey{  using nitrokey::misc::strcpyT; -constexpr int max_string_field_length = 2*1024; //storage's status string is ~1k  //storage commands diff --git a/libnitrokey/NitrokeyManager.h b/libnitrokey/NitrokeyManager.h index ba61793..20db98d 100644 --- a/libnitrokey/NitrokeyManager.h +++ b/libnitrokey/NitrokeyManager.h @@ -49,6 +49,7 @@ typename T::CommandPayload get_payload(){  }  #include "nk_strndup.h" +constexpr int max_string_field_length = 2*1024; //storage's status string is ~1k      class NitrokeyManager {      public: | 
