diff options
| -rw-r--r-- | NitrokeyManager.cc | 67 | ||||
| -rw-r--r-- | command_id.cc | 3 | ||||
| -rw-r--r-- | include/command_id.h | 1 | ||||
| -rw-r--r-- | include/stick10_commands_0.8.h | 111 | ||||
| -rw-r--r-- | unittest/constants.py | 2 | ||||
| -rw-r--r-- | unittest/test3.cc | 111 | ||||
| -rw-r--r-- | unittest/test_pro.py | 33 | 
7 files changed, 169 insertions, 159 deletions
| diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index e80f9b5..46c09df 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -228,23 +228,30 @@ namespace nitrokey{                                                         uint64_t hotp_counter, bool use_8_digits, bool use_enter,                                                         bool use_tokenID, const char *token_ID,                                                         const char *temporary_password) const { -      auto payload = get_payload<stick10_08::WriteToHOTPSlot>(); -      strcpyT(payload.temporary_admin_password, temporary_password); +      auto payload2 = get_payload<stick10_08::SendOTPData>(); +      strcpyT(payload2.temporary_admin_password, temporary_password); +      strcpyT(payload2.data, slot_name); +      payload2.length = strlen((const char *) payload2.data); +      payload2.setTypeName(); +      stick10_08::SendOTPData::CommandTransaction::run(*device, payload2); + +      payload2 = get_payload<stick10_08::SendOTPData>(); +      strcpyT(payload2.temporary_admin_password, temporary_password);        auto secret_bin = misc::hex_string_to_byte(secret); -      vector_copy(payload.slot_secret, secret_bin); +      vector_copy(payload2.data, secret_bin); +      payload2.length = strlen((const char *) payload2.data); +      payload2.setTypeSecret(); +      stick10_08::SendOTPData::CommandTransaction::run(*device, payload2); + +      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; - -      auto payload2 = get_payload<stick10_08::WriteToHOTPSlot_2>(); -      strcpyT(payload2.temporary_admin_password, temporary_password); -      payload2.slot_number = slot_number; -      strcpyT(payload2.slot_name, slot_name); -      payload2.slot_counter = hotp_counter; - -      stick10_08::WriteToHOTPSlot::CommandTransaction::run(*device, payload); -      stick10_08::WriteToHOTPSlot_2::CommandTransaction::run(*device, payload2); +      payload.slot_counter_or_interval = hotp_counter; +      payload.slot_number = slot_number; +      stick10_08::WriteToOTPSlot::CommandTransaction::run(*device, payload);      }      void NitrokeyManager::write_HOTP_slot_authorize(uint8_t slot_number, const char *slot_name, const char *secret, @@ -302,23 +309,31 @@ namespace nitrokey{                                                         uint16_t time_window, bool use_8_digits, bool use_enter,                                                         bool use_tokenID, const char *token_ID,                                                         const char *temporary_password) const { -      auto payload = get_payload<stick10_08::WriteToTOTPSlot>(); -      strcpyT(payload.temporary_admin_password, temporary_password); + +      auto payload2 = get_payload<stick10_08::SendOTPData>(); +      strcpyT(payload2.temporary_admin_password, temporary_password); +      strcpyT(payload2.data, slot_name); +      payload2.length = strlen((const char *) payload2.data); +      payload2.setTypeName(); +      stick10_08::SendOTPData::CommandTransaction::run(*device, payload2); + +      payload2 = get_payload<stick10_08::SendOTPData>(); +      strcpyT(payload2.temporary_admin_password, temporary_password);        auto secret_bin = misc::hex_string_to_byte(secret); -      vector_copy(payload.slot_secret, secret_bin); +      vector_copy(payload2.data, secret_bin); +      payload2.length = strlen((const char *) payload2.data); +      payload2.setTypeSecret(); +      stick10_08::SendOTPData::CommandTransaction::run(*device, payload2); + +      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; - -      auto payload2 = get_payload<stick10_08::WriteToTOTPSlot_2>(); -      strcpyT(payload2.temporary_admin_password, temporary_password); -      payload2.slot_number = slot_number; -      strcpyT(payload2.slot_name, slot_name); -      payload2.slot_interval= time_window; - -      stick10_08::WriteToTOTPSlot::CommandTransaction::run(*device, payload); -      stick10_08::WriteToTOTPSlot_2::CommandTransaction::run(*device, payload2); +      payload.slot_counter_or_interval = time_window; +      payload.slot_number = 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, @@ -583,8 +598,8 @@ namespace nitrokey{      bool NitrokeyManager::is_authorization_command_supported(){          auto m = std::unordered_map<DeviceModel , int, EnumClassHash>({ -                                                     {DeviceModel::PRO, 7}, -                                                     {DeviceModel::STORAGE, 43}, +                                               {DeviceModel::PRO, 7}, +                                               {DeviceModel::STORAGE, 43},           });        auto status_p = GetStatus::CommandTransaction::run(*device);        return status_p.data().firmware_version <= m[device->get_device_model()]; diff --git a/command_id.cc b/command_id.cc index a93d05c..f76a358 100644 --- a/command_id.cc +++ b/command_id.cc @@ -142,6 +142,9 @@ const char *commandid_to_string(CommandID id) {      case CommandID::WRITE_TO_SLOT_2:        return "WRITE_TO_SLOT_2";        break; +    case CommandID::SEND_OTP_DATA: +      return "SEND_OTP_DATA"; +      break;    }    return "UNKNOWN";  } diff --git a/include/command_id.h b/include/command_id.h index 1f7affc..346b750 100644 --- a/include/command_id.h +++ b/include/command_id.h @@ -66,6 +66,7 @@ enum class CommandID : uint8_t {    CHANGE_USER_PIN = 0x14,    CHANGE_ADMIN_PIN = 0x15,    WRITE_TO_SLOT_2 = 0x16, +  SEND_OTP_DATA = 0x17,    ENABLE_CRYPTED_PARI = 0x20,    DISABLE_CRYPTED_PARI = 0x20 + 1, //@unused diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h index 3644c4d..e880c0a 100644 --- a/include/stick10_commands_0.8.h +++ b/include/stick10_commands_0.8.h @@ -44,47 +44,33 @@ namespace nitrokey {                      CommandTransaction;              }; -            class WriteToHOTPSlot : Command<CommandID::WRITE_TO_SLOT> { +            class SendOTPData : Command<CommandID::SEND_OTP_DATA> {                  //admin auth              public:                  struct CommandPayload {                      uint8_t temporary_admin_password[25]; -                    uint8_t slot_secret[20]; -                    union { -                        uint8_t _slot_config; -                        struct { -                            bool use_8_digits   : 1; -                            bool use_enter      : 1; -                            bool use_tokenID    : 1; -                        }; -                    }; -                    union { -                        uint8_t slot_token_id[13]; /** OATH Token Identifier */ -                        struct { /** @see https://openauthentication.org/token-specs/ */ -                            uint8_t omp[2]; -                            uint8_t tt[2]; -                            uint8_t mui[8]; -                            uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805 -                        } slot_token_fields; -                    }; +                    uint8_t type; //0-secret, 1-name +                    uint8_t id; //multiple reports for values longer than 30 bytes +                    uint8_t length; //data length +                    uint8_t data[30]; //data, does not need null termination                      bool isValid() const { return true; } +                    void setTypeName(){ +                      type = 'N'; +                    } +                    void setTypeSecret(){ +                      type = 'S'; +                    } +                      std::string dissect() const {                        std::stringstream ss;                        ss << "temporary_admin_password:\t" << temporary_admin_password << std::endl; -                      ss << "slot_secret:" << std::endl -                         << ::nitrokey::misc::hexdump((const char *) (&slot_secret), sizeof slot_secret); -                      ss << "slot_config:\t" << std::bitset<8>((int) _slot_config) << std::endl; -                      ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl; -                      ss << "\tuse_enter(1):\t" << use_enter << std::endl; -                      ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl; - -                      ss << "slot_token_id:\t"; -                      for (auto i : slot_token_id) -                        ss << std::hex << std::setw(2) << std::setfill('0') << (int) i << " "; -                      ss << std::endl; - +                      ss << "type:\t" << type << std::endl; +                      ss << "id:\t" << (int)id << std::endl; +                      ss << "length:\t" << (int)length << std::endl; +                      ss << "data:" << std::endl +                         << ::nitrokey::misc::hexdump((const char *) (&data), sizeof data);                        return ss.str();                      }                  } __packed; @@ -93,42 +79,16 @@ namespace nitrokey {                      CommandTransaction;              }; -            class WriteToHOTPSlot_2 : Command<CommandID::WRITE_TO_SLOT_2> { +            class WriteToOTPSlot : Command<CommandID::WRITE_TO_SLOT> { +                //admin auth              public:                  struct CommandPayload {                      uint8_t temporary_admin_password[25];                      uint8_t slot_number; -                    uint8_t slot_name[15];                      union { -                        uint64_t slot_counter; +                        uint64_t slot_counter_or_interval;                          uint8_t slot_counter_s[8];                      } __packed; - -                    bool isValid() const { return !(slot_number & 0xF0); } - -                    std::string dissect() const { -                      std::stringstream ss; -                      ss << "temporary_admin_password:\t" << temporary_admin_password << std::endl; -                      ss << "slot_number:\t" << (int) (slot_number) << std::endl; -                      ss << "slot_name:\t" << slot_name << std::endl; -                      ss << "slot_counter:\t[" << (int) slot_counter << "]\t" -                         << ::nitrokey::misc::hexdump((const char *) (&slot_counter), sizeof slot_counter, false); - -                      return ss.str(); -                    } -                } __packed; - -                typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> -                    CommandTransaction; -            }; - - -            class WriteToTOTPSlot : Command<CommandID::WRITE_TO_SLOT> { -                //admin auth -            public: -                struct CommandPayload { -                    uint8_t temporary_admin_password[25]; -                    uint8_t slot_secret[20];                      union {                          uint8_t _slot_config;                          struct { @@ -152,12 +112,13 @@ namespace nitrokey {                      std::string dissect() const {                        std::stringstream ss;                        ss << "temporary_admin_password:\t" << temporary_admin_password << std::endl; -                      ss << "slot_secret:" << std::endl -                         << ::nitrokey::misc::hexdump((const char *) (&slot_secret), sizeof slot_secret);                        ss << "slot_config:\t" << std::bitset<8>((int) _slot_config) << std::endl;                        ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;                        ss << "\tuse_enter(1):\t" << use_enter << std::endl;                        ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl; +                      ss << "slot_number:\t" << (int) (slot_number) << std::endl; +                      ss << "slot_counter_or_interval:\t[" << (int) slot_counter_or_interval << "]\t" +                         << ::nitrokey::misc::hexdump((const char *) (&slot_counter_or_interval), sizeof slot_counter_or_interval, false);                        ss << "slot_token_id:\t";                        for (auto i : slot_token_id) @@ -172,32 +133,6 @@ namespace nitrokey {                      CommandTransaction;              }; -            class WriteToTOTPSlot_2 : Command<CommandID::WRITE_TO_SLOT_2> { -            public: -                struct CommandPayload { -                    uint8_t temporary_admin_password[25]; -                    uint8_t slot_number; -                    uint8_t slot_name[15]; -                    uint16_t slot_interval; - -                    bool isValid() const { return !(slot_number & 0xF0); } - -                    std::string dissect() const { -                      std::stringstream ss; -                      ss << "temporary_admin_password:\t" << temporary_admin_password << std::endl; -                      ss << "slot_number:\t" << (int) (slot_number) << std::endl; -                      ss << "slot_name:\t" << slot_name << std::endl; -                      ss << "slot_interval:\t" << (int)slot_interval << std::endl; - -                      return ss.str(); -                    } -                } __packed; - -                typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> -                    CommandTransaction; -            }; - -              class GetHOTP : Command<CommandID::GET_CODE> {              public:                  struct CommandPayload { diff --git a/unittest/constants.py b/unittest/constants.py index 78a219b..3c19a9b 100644 --- a/unittest/constants.py +++ b/unittest/constants.py @@ -2,7 +2,7 @@ from enum import Enum  from misc import to_hex  RFC_SECRET_HR = '12345678901234567890' -RFC_SECRET = to_hex(RFC_SECRET_HR)  # '12345678901234567890' +RFC_SECRET = to_hex(RFC_SECRET_HR)  # '3031323334353637383930...'  # print( repr((RFC_SECRET, RFC_SECRET_, len(RFC_SECRET))) ) diff --git a/unittest/test3.cc b/unittest/test3.cc index 7f779a5..7b37a60 100644 --- a/unittest/test3.cc +++ b/unittest/test3.cc @@ -49,18 +49,26 @@ TEST_CASE("write slot", "[pronew]"){    connect_and_setup(stick);    authorize(stick); -  auto p = get_payload<WriteToHOTPSlot>(); -  strcpyT(p.slot_secret, RFC_SECRET); -  strcpyT(p.temporary_admin_password, temporary_password); -  p.use_8_digits = true; -  stick10_08::WriteToHOTPSlot::CommandTransaction::run(stick, p); +  auto p2 = get_payload<SendOTPData>(); +  strcpyT(p2.temporary_admin_password, temporary_password); +  p2.setTypeName(); +  strcpyT(p2.data, "test name aaa"); +  p2.length = strlen((const char *) p2.data); +  stick10_08::SendOTPData::CommandTransaction::run(stick, p2); -  auto p2 = get_payload<WriteToHOTPSlot_2>(); +  p2 = get_payload<SendOTPData>();    strcpyT(p2.temporary_admin_password, temporary_password); -  p2.slot_number = 0 + 0x10; -  p2.slot_counter = 0; -  strcpyT(p2.slot_name, "test name aaa"); -  stick10_08::WriteToHOTPSlot_2::CommandTransaction::run(stick, p2); +  strcpyT(p2.data, RFC_SECRET); +  p2.length = strlen(RFC_SECRET); +  p2.setTypeSecret(); +  stick10_08::SendOTPData::CommandTransaction::run(stick, p2); + +  auto p = get_payload<WriteToOTPSlot>(); +  strcpyT(p.temporary_admin_password, temporary_password); +  p.use_8_digits = true; +  p.slot_number = 0 + 0x10; +  p.slot_counter_or_interval = 0; +  stick10_08::WriteToOTPSlot::CommandTransaction::run(stick, p);    auto pc = get_payload<WriteGeneralConfig>();    pc.enable_user_password = 0; @@ -119,23 +127,34 @@ TEST_CASE("authorize user HOTP", "[pronew]") {    connect_and_setup(stick);    authorize(stick); -  auto p = get_payload<WriteGeneralConfig>(); -  p.enable_user_password = 1; -  strcpyT(p.temporary_admin_password, temporary_password); -  WriteGeneralConfig::CommandTransaction::run(stick, p); +  { +    auto p = get_payload<WriteGeneralConfig>(); +    p.enable_user_password = 1; +    strcpyT(p.temporary_admin_password, temporary_password); +    WriteGeneralConfig::CommandTransaction::run(stick, p); +  } + +  auto p2 = get_payload<SendOTPData>(); +  strcpyT(p2.temporary_admin_password, temporary_password); +  p2.setTypeName(); +  strcpyT(p2.data, "test name aaa"); +  p2.length = strlen((const char *) p2.data); +  stick10_08::SendOTPData::CommandTransaction::run(stick, p2); + +  p2 = get_payload<SendOTPData>(); +  strcpyT(p2.temporary_admin_password, temporary_password); +  strcpyT(p2.data, RFC_SECRET); +  p2.length = strlen(RFC_SECRET); +  p2.setTypeSecret(); +  stick10_08::SendOTPData::CommandTransaction::run(stick, p2); -  auto pw = get_payload<WriteToHOTPSlot>(); -  strcpyT(pw.slot_secret, RFC_SECRET); -  strcpyT(pw.temporary_admin_password, temporary_password); -  pw.use_8_digits = true; -  WriteToHOTPSlot::CommandTransaction::run(stick, pw); +  auto p = get_payload<WriteToOTPSlot>(); +  strcpyT(p.temporary_admin_password, temporary_password); +  p.use_8_digits = true; +  p.slot_number = 0 + 0x10; +  p.slot_counter_or_interval = 0; +  stick10_08::WriteToOTPSlot::CommandTransaction::run(stick, p); -  auto pw2 = get_payload<WriteToHOTPSlot_2>(); -  strcpyT(pw2.temporary_admin_password, temporary_password); -  pw2.slot_number = 0 + 0x10; -  pw2.slot_counter = 0; -  strcpyT(pw2.slot_name, "test name aaa"); -  WriteToHOTPSlot_2::CommandTransaction::run(stick, pw2);    auto p3 = get_payload<GetHOTP>();    p3.slot_number = 0 + 0x10; @@ -161,23 +180,33 @@ TEST_CASE("authorize user TOTP", "[pronew]") {    connect_and_setup(stick);    authorize(stick); -  auto p = get_payload<WriteGeneralConfig>(); -  p.enable_user_password = 1; -  strcpyT(p.temporary_admin_password, temporary_password); -  WriteGeneralConfig::CommandTransaction::run(stick, p); +  { +    auto p = get_payload<WriteGeneralConfig>(); +    p.enable_user_password = 1; +    strcpyT(p.temporary_admin_password, temporary_password); +    WriteGeneralConfig::CommandTransaction::run(stick, p); +  } -  auto pw = get_payload<WriteToTOTPSlot>(); -  strcpyT(pw.slot_secret, RFC_SECRET); -  strcpyT(pw.temporary_admin_password, temporary_password); -  pw.use_8_digits = true; -  WriteToTOTPSlot::CommandTransaction::run(stick, pw); - -  auto pw2 = get_payload<WriteToTOTPSlot_2>(); -  strcpyT(pw2.temporary_admin_password, temporary_password); -  pw2.slot_number = 0 + 0x20; -  pw2.slot_interval= 30; -  strcpyT(pw2.slot_name, "test name TOTP"); -  WriteToTOTPSlot_2::CommandTransaction::run(stick, pw2); +  auto p2 = get_payload<SendOTPData>(); +  strcpyT(p2.temporary_admin_password, temporary_password); +  p2.setTypeName(); +  strcpyT(p2.data, "test name TOTP"); +  p2.length = strlen((const char *) p2.data); +  stick10_08::SendOTPData::CommandTransaction::run(stick, p2); + +  p2 = get_payload<SendOTPData>(); +  strcpyT(p2.temporary_admin_password, temporary_password); +  strcpyT(p2.data, RFC_SECRET); +  p2.length = strlen(RFC_SECRET); +  p2.setTypeSecret(); +  stick10_08::SendOTPData::CommandTransaction::run(stick, p2); + +  auto p = get_payload<WriteToOTPSlot>(); +  strcpyT(p.temporary_admin_password, temporary_password); +  p.use_8_digits = true; +  p.slot_number = 0 + 0x20; +  p.slot_counter_or_interval = 30; +  stick10_08::WriteToOTPSlot::CommandTransaction::run(stick, p);    auto p_get_totp = get_payload<GetTOTP>();    p_get_totp.slot_number = 0 + 0x20; diff --git a/unittest/test_pro.py b/unittest/test_pro.py index a9e9fa4..3632ecd 100644 --- a/unittest/test_pro.py +++ b/unittest/test_pro.py @@ -536,7 +536,7 @@ def test_HOTP_slots_read_write_counter(C, counter):      lib_res = []      for slot_number in range(3):          assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK -        assert C.NK_write_hotp_slot(slot_number, 'null_secret', secret, counter, use_8_digits, False, False, "", +        assert C.NK_write_hotp_slot(slot_number, 'HOTP rw' + str(slot_number), secret, counter, use_8_digits, False, False, "",                                      DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK          code_device = str(C.NK_get_hotp_code(slot_number))          code_device = '0'+code_device if len(code_device) < 6 else code_device @@ -546,7 +546,7 @@ def test_HOTP_slots_read_write_counter(C, counter):  @pytest.mark.parametrize("period", [30,60] ) -@pytest.mark.parametrize("time", range(20,70,20) ) +@pytest.mark.parametrize("time", range(21,70,20) )  def test_TOTP_slots_read_write_at_time_period(C, time, period):      secret = RFC_SECRET      oath = pytest.importorskip("oath") @@ -561,7 +561,7 @@ def test_TOTP_slots_read_write_at_time_period(C, time, period):      lib_res = []      for slot_number in range(15):          assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK -        assert C.NK_write_totp_slot(slot_number, 'null_secret', secret, period, use_8_digits, False, False, "", +        assert C.NK_write_totp_slot(slot_number, 'TOTP rw' + str(slot_number), secret, period, use_8_digits, False, False, "",                                      DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK          assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK          assert C.NK_totp_set_time(time) == DeviceErrorCode.STATUS_OK @@ -572,5 +572,32 @@ def test_TOTP_slots_read_write_at_time_period(C, time, period):      assert dev_res == lib_res +@pytest.mark.parametrize("secret", [RFC_SECRET, 2*RFC_SECRET] ) +def test_TOTP_secrets(C, secret): +    slot_number = 0 +    time = 0 +    period = 30 +    oath = pytest.importorskip("oath") +    lib_at = lambda t: oath.totp(secret, t=t, period=period) +    PIN_protection = False +    use_8_digits = False +    T = 0 +    assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK +    assert C.NK_write_config(255, 255, 255, PIN_protection, not PIN_protection, +                             DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK +    dev_res = [] +    lib_res = [] +    assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK +    assert C.NK_write_totp_slot(slot_number, 'TOTP secret' + str(slot_number), secret, period, use_8_digits, False, False, "", +                                DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK +    assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK +    assert C.NK_totp_set_time(time) == DeviceErrorCode.STATUS_OK +    code_device = str(C.NK_get_totp_code(slot_number, T, 0, period)) +    code_device = '0'+code_device if len(code_device) < 6 else code_device +    dev_res += (time, code_device) +    lib_res += (time, lib_at(time)) +    assert dev_res == lib_res + + | 
