From 130d7f12e42505a33f41073983d868ca0c3c78d1 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Tue, 8 Nov 2016 17:03:48 +0100 Subject: Fix for auth issue in NK Pro for commands EraseSlot, WriteToSlot, GetCode + tests Signed-off-by: Szczepan Zalega --- include/command_id.h | 1 + include/stick10_commands.h | 4 + include/stick10_commands_0.8.h | 178 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 include/stick10_commands_0.8.h (limited to 'include') diff --git a/include/command_id.h b/include/command_id.h index a3806f0..1f7affc 100644 --- a/include/command_id.h +++ b/include/command_id.h @@ -65,6 +65,7 @@ enum class CommandID : uint8_t { FACTORY_RESET = 0x13, CHANGE_USER_PIN = 0x14, CHANGE_ADMIN_PIN = 0x15, + WRITE_TO_SLOT_2 = 0x16, ENABLE_CRYPTED_PARI = 0x20, DISABLE_CRYPTED_PARI = 0x20 + 1, //@unused diff --git a/include/stick10_commands.h b/include/stick10_commands.h index f02fd70..5ae2591 100644 --- a/include/stick10_commands.h +++ b/include/stick10_commands.h @@ -48,6 +48,7 @@ class EraseSlot : Command { public: struct CommandPayload { uint8_t slot_number; + uint8_t temporary_admin_password[25]; bool isValid() const { return !(slot_number & 0xF0); } std::string dissect() const { @@ -137,6 +138,7 @@ class WriteToHOTPSlot : Command { }; class WriteToTOTPSlot : Command { + //admin auth public: struct CommandPayload { uint8_t slot_number; @@ -182,6 +184,7 @@ class WriteToTOTPSlot : Command { }; class GetTOTP : Command { + //user auth public: struct CommandPayload { uint8_t slot_number; @@ -612,6 +615,7 @@ class PasswordSafeSendSlotViaHID : Command { // TODO "Device::passwordSafeSendSlotDataViaHID" class WriteGeneralConfig : Command { + //admin auth public: struct CommandPayload { union{ diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h new file mode 100644 index 0000000..037a777 --- /dev/null +++ b/include/stick10_commands_0.8.h @@ -0,0 +1,178 @@ +// +// Created by sz on 08.11.16. +// + +#ifndef LIBNITROKEY_STICK10_COMMANDS_0_8_H +#define LIBNITROKEY_STICK10_COMMANDS_0_8_H + +#include +#include +#include +#include +#include "inttypes.h" +#include "command.h" +#include "device_proto.h" + +namespace nitrokey { + namespace proto { + +/* + * Stick10 protocol definition + */ + namespace stick10_08 { + + class EraseSlot : Command { + public: + struct CommandPayload { + uint8_t slot_number; + uint8_t temporary_admin_password[25]; + + bool isValid() const { return !(slot_number & 0xF0); } + std::string dissect() const { + std::stringstream ss; + ss << "slot_number:\t" << (int)(slot_number) << std::endl; + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + }; + + class WriteToHOTPSlot : Command { + //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; + }; + + bool isValid() const { return true; } + + 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; + + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + }; + + class WriteToHOTPSlot_2 : Command { + public: + struct CommandPayload { + uint8_t temporary_admin_password[25]; + uint8_t slot_number; + uint8_t slot_name[15]; + union { + uint64_t slot_counter; + 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 + CommandTransaction; + }; + + + class GetTOTP : Command { + //user auth + public: + struct CommandPayload { + uint8_t slot_number; + uint64_t challenge; + uint64_t last_totp_time; + uint8_t last_interval; + uint8_t user_temporary_password[25]; + + bool isValid() const { return !(slot_number & 0xF0); } + std::string dissect() const { + std::stringstream ss; + ss << "slot_number:\t" << (int)(slot_number) << std::endl; + ss << "challenge:\t" << (challenge) << std::endl; + ss << "last_totp_time:\t" << (last_totp_time) << std::endl; + ss << "last_interval:\t" << (int)(last_interval) << std::endl; + return ss.str(); + } + } __packed; + + struct ResponsePayload { + union { + uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1 + struct { + uint32_t code; + union{ + uint8_t _slot_config; + struct{ + bool use_8_digits : 1; + bool use_enter : 1; + bool use_tokenID : 1; + }; + }; + } __packed ; + } __packed ; + + bool isValid() const { return true; } + std::string dissect() const { + std::stringstream ss; + ss << "code:\t" << (code) << std::endl; + 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; + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + }; + + + } + } +} +#endif //LIBNITROKEY_STICK10_COMMANDS_0_8_H -- cgit v1.2.3 From 119ea0b111c9ca46fda32911c1c8c33b36aad3db Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Tue, 8 Nov 2016 18:58:17 +0100 Subject: Authorization fix: GetHOTP and WriteGeneralConfig + test Signed-off-by: Szczepan Zalega --- command_id.cc | 3 ++ include/stick10_commands_0.8.h | 83 +++++++++++++++++++++++++++++++++++++++++- unittest/test3.cc | 69 ++++++++++++++++++++++++++++++++--- 3 files changed, 149 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/command_id.cc b/command_id.cc index 9512b7d..a93d05c 100644 --- a/command_id.cc +++ b/command_id.cc @@ -139,6 +139,9 @@ const char *commandid_to_string(CommandID id) { return "DETECT_SC_AES"; case CommandID::NEW_AES_KEY: return "NEW_AES_KEY"; + case CommandID::WRITE_TO_SLOT_2: + return "WRITE_TO_SLOT_2"; + break; } return "UNKNOWN"; } diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h index 037a777..0c6633c 100644 --- a/include/stick10_commands_0.8.h +++ b/include/stick10_commands_0.8.h @@ -12,6 +12,7 @@ #include "inttypes.h" #include "command.h" #include "device_proto.h" +#include "stick10_commands.h" namespace nitrokey { namespace proto { @@ -20,6 +21,8 @@ namespace nitrokey { * Stick10 protocol definition */ namespace stick10_08 { + using stick10::FirstAuthenticate; + using stick10::UserAuthenticate; class EraseSlot : Command { public: @@ -117,20 +120,68 @@ namespace nitrokey { CommandTransaction; }; + class GetHOTP : Command { + public: + struct CommandPayload { + uint8_t temporary_user_password[25]; + uint8_t slot_number; + + bool isValid() const { return (slot_number & 0xF0); } + std::string dissect() const { + std::stringstream ss; + ss << "temporary_user_password:\t" << temporary_user_password << std::endl; + ss << "slot_number:\t" << (int)(slot_number) << std::endl; + return ss.str(); + } + } __packed; + + struct ResponsePayload { + union { + uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1 + struct { + uint32_t code; + union{ + uint8_t _slot_config; + struct{ + bool use_8_digits : 1; + bool use_enter : 1; + bool use_tokenID : 1; + }; + }; + } __packed; + } __packed; + + bool isValid() const { return true; } + std::string dissect() const { + std::stringstream ss; + ss << "code:\t" << (code) << std::endl; + 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; + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + }; + class GetTOTP : Command { //user auth public: struct CommandPayload { + uint8_t temporary_user_password[25]; uint8_t slot_number; uint64_t challenge; uint64_t last_totp_time; uint8_t last_interval; - uint8_t user_temporary_password[25]; bool isValid() const { return !(slot_number & 0xF0); } std::string dissect() const { std::stringstream ss; + ss << "temporary_user_password:\t" << temporary_user_password << std::endl; ss << "slot_number:\t" << (int)(slot_number) << std::endl; ss << "challenge:\t" << (challenge) << std::endl; ss << "last_totp_time:\t" << (last_totp_time) << std::endl; @@ -172,6 +223,36 @@ namespace nitrokey { }; + class WriteGeneralConfig : Command { + //admin auth + public: + struct CommandPayload { + union{ + uint8_t config[5]; + struct{ + uint8_t numlock; /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */ + uint8_t capslock; /** same as numlock */ + uint8_t scrolllock; /** same as numlock */ + uint8_t enable_user_password; + uint8_t delete_user_password; + }; + }; + uint8_t temporary_admin_password[25]; + + std::string dissect() const { + std::stringstream ss; + ss << "numlock:\t" << (int)numlock << std::endl; + ss << "capslock:\t" << (int)capslock << std::endl; + ss << "scrolllock:\t" << (int)scrolllock << std::endl; + ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl; + ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl; + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + }; } } } diff --git a/unittest/test3.cc b/unittest/test3.cc index 6fab862..226e35c 100644 --- a/unittest/test3.cc +++ b/unittest/test3.cc @@ -16,15 +16,13 @@ const char * RFC_SECRET = "12345678901234567890"; #include #include "device_proto.h" #include "log.h" -#include "stick10_commands.h" #include "stick10_commands_0.8.h" //#include "stick20_commands.h" using namespace std; using namespace nitrokey::device; using namespace nitrokey::proto; -//using namespace nitrokey::proto::stick10_08; -using namespace nitrokey::proto::stick10; +using namespace nitrokey::proto::stick10_08; using namespace nitrokey::log; using namespace nitrokey::misc; @@ -39,6 +37,11 @@ void authorize(Stick10 &stick) { strcpy((char *) (authreq.card_password), default_admin_pin); strcpy((char *) (authreq.temporary_password), temporary_password); FirstAuthenticate::CommandTransaction::run(stick, authreq); + + auto user_auth = get_payload(); + strcpyT(user_auth.temporary_password, temporary_password); + strcpyT(user_auth.card_password, default_user_pin); + UserAuthenticate::CommandTransaction::run(stick, user_auth); } TEST_CASE("write slot", "[pronew]"){ @@ -46,7 +49,6 @@ TEST_CASE("write slot", "[pronew]"){ connect_and_setup(stick); auto p = get_payload(); -// p.slot_number = 0 + 0x10; strcpyT(p.slot_secret, RFC_SECRET); strcpyT(p.temporary_admin_password, temporary_password); p.use_8_digits = true; @@ -71,8 +73,65 @@ TEST_CASE("erase slot", "[pronew]"){ connect_and_setup(stick); authorize(stick); + auto p3 = get_payload(); + p3.slot_number = 0 + 0x10; + GetHOTP::CommandTransaction::run(stick, p3); + auto erase_payload = get_payload(); - erase_payload.slot_number = 1 + 0x10; + erase_payload.slot_number = 0 + 0x10; strcpyT(erase_payload.temporary_admin_password, temporary_password); stick10_08::EraseSlot::CommandTransaction::run(stick, erase_payload); + + auto p4 = get_payload(); + p4.slot_number = 0 + 0x10; + REQUIRE_THROWS( + GetHOTP::CommandTransaction::run(stick, p4) + ); +} + +TEST_CASE("write general config", "[pronew]") { + Stick10 stick; + connect_and_setup(stick); + authorize(stick); + + auto p = get_payload(); + p.enable_user_password = 1; + REQUIRE_THROWS( + WriteGeneralConfig::CommandTransaction::run(stick, p); + ); + strcpyT(p.temporary_admin_password, temporary_password); + WriteGeneralConfig::CommandTransaction::run(stick, p); +} + +TEST_CASE("authorize user OTP", "[pronew]") { + Stick10 stick; + connect_and_setup(stick); + authorize(stick); + + auto p = get_payload(); + p.enable_user_password = 1; + strcpyT(p.temporary_admin_password, temporary_password); + WriteGeneralConfig::CommandTransaction::run(stick, p); + + auto pw = get_payload(); + strcpyT(pw.slot_secret, RFC_SECRET); + strcpyT(pw.temporary_admin_password, temporary_password); + pw.use_8_digits = true; + WriteToHOTPSlot::CommandTransaction::run(stick, pw); + + auto pw2 = get_payload(); + 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(); + p3.slot_number = 0 + 0x10; + REQUIRE_THROWS( + GetHOTP::CommandTransaction::run(stick, p3); + ); + strcpyT(p3.temporary_user_password, temporary_password); + GetHOTP::CommandTransaction::run(stick, p3); + } \ No newline at end of file -- cgit v1.2.3 From f76ac655fff3df7eb0e645ca39d18510714b0039 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Wed, 9 Nov 2016 14:29:18 +0100 Subject: Authorization fix: GetTOTP and WriteToTOTPSLot + test Signed-off-by: Szczepan Zalega --- include/stick10_commands_0.8.h | 77 ++++++++++++++++++++++++++++++++++++++++++ unittest/test3.cc | 46 +++++++++++++++++++++++-- 2 files changed, 121 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h index 0c6633c..cee0d78 100644 --- a/include/stick10_commands_0.8.h +++ b/include/stick10_commands_0.8.h @@ -23,6 +23,7 @@ namespace nitrokey { namespace stick10_08 { using stick10::FirstAuthenticate; using stick10::UserAuthenticate; + using stick10::SetTime; class EraseSlot : Command { public: @@ -120,6 +121,82 @@ namespace nitrokey { CommandTransaction; }; + + class WriteToTOTPSlot : Command { + //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; + }; + + bool isValid() const { return true; } + + 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; + + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + }; + + class WriteToTOTPSlot_2 : Command { + 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 + CommandTransaction; + }; + + class GetHOTP : Command { public: struct CommandPayload { diff --git a/unittest/test3.cc b/unittest/test3.cc index 226e35c..8a9423f 100644 --- a/unittest/test3.cc +++ b/unittest/test3.cc @@ -103,7 +103,7 @@ TEST_CASE("write general config", "[pronew]") { WriteGeneralConfig::CommandTransaction::run(stick, p); } -TEST_CASE("authorize user OTP", "[pronew]") { +TEST_CASE("authorize user HOTP", "[pronew]") { Stick10 stick; connect_and_setup(stick); authorize(stick); @@ -132,6 +132,48 @@ TEST_CASE("authorize user OTP", "[pronew]") { GetHOTP::CommandTransaction::run(stick, p3); ); strcpyT(p3.temporary_user_password, temporary_password); - GetHOTP::CommandTransaction::run(stick, p3); + auto code_response = GetHOTP::CommandTransaction::run(stick, p3); + REQUIRE(code_response.data().code == 1284755224); + +} + + +TEST_CASE("authorize user TOTP", "[pronew]") { + Stick10 stick; + connect_and_setup(stick); + authorize(stick); + + auto p = get_payload(); + p.enable_user_password = 1; + strcpyT(p.temporary_admin_password, temporary_password); + WriteGeneralConfig::CommandTransaction::run(stick, p); + + auto pw = get_payload(); + 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(); + 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 p_get_totp = get_payload(); + p_get_totp.slot_number = 0 + 0x20; + + REQUIRE_THROWS( + GetTOTP::CommandTransaction::run(stick, p_get_totp); + ); + strcpyT(p_get_totp.temporary_user_password, temporary_password); + + auto p_set_time = get_payload(); + p_set_time.reset = 1; + p_set_time.time = 59; + SetTime::CommandTransaction::run(stick, p_set_time); + auto code = GetTOTP::CommandTransaction::run(stick, p_get_totp); + REQUIRE(code.data().code == 94287082); } \ No newline at end of file -- cgit v1.2.3 From 90bf7f564c50bf48799056179dbc5a09b7782d27 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Wed, 9 Nov 2016 18:30:07 +0100 Subject: Check firware version in Pro 0.8 test Signed-off-by: Szczepan Zalega --- include/stick10_commands_0.8.h | 1 + unittest/test3.cc | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'include') diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h index cee0d78..9099b3d 100644 --- a/include/stick10_commands_0.8.h +++ b/include/stick10_commands_0.8.h @@ -24,6 +24,7 @@ namespace nitrokey { using stick10::FirstAuthenticate; using stick10::UserAuthenticate; using stick10::SetTime; + using stick10::GetStatus; class EraseSlot : Command { public: diff --git a/unittest/test3.cc b/unittest/test3.cc index bd6f2a5..7f779a5 100644 --- a/unittest/test3.cc +++ b/unittest/test3.cc @@ -148,6 +148,13 @@ TEST_CASE("authorize user HOTP", "[pronew]") { } +TEST_CASE("check firmware version", "[pronew]") { + Stick10 stick; + connect_and_setup(stick); + + auto p = GetStatus::CommandTransaction::run(stick); + REQUIRE(p.data().firmware_version == 8); +} TEST_CASE("authorize user TOTP", "[pronew]") { Stick10 stick; -- cgit v1.2.3 From 2ba87abdb5c69e3d72b88164030ed5633986a63d Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Wed, 9 Nov 2016 19:22:46 +0100 Subject: Convinient function for checking if authorization command is supported Signed-off-by: Szczepan Zalega --- NitrokeyManager.cc | 16 +++++++++++++++- include/NitrokeyManager.h | 4 ++++ include/device.h | 9 +++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index 20f4f14..b254071 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -3,6 +3,7 @@ #include "include/NitrokeyManager.h" #include "include/LibraryException.h" #include +#include #include "include/misc.h" namespace nitrokey{ @@ -35,7 +36,11 @@ namespace nitrokey{ // package type to auth, auth type [Authorize,UserAuthorize] template - void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device){ + void NitrokeyManager::authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device){ + if (!is_authorization_command_supported()){ + Log::instance()("Authorization command not supported, skipping", Loglevel::WARNING); + return; + } auto auth = get_payload(); strcpyT(auth.temporary_password, admin_temporary_password); auth.crc_to_authorize = S::CommandTransaction::getCRC(package); @@ -480,6 +485,15 @@ namespace nitrokey{ return v; } + bool NitrokeyManager::is_authorization_command_supported(){ + auto m = std::unordered_map({ + {DeviceModel::PRO, 7}, + {DeviceModel::STORAGE, 43}, + }); + auto status_p = GetStatus::CommandTransaction::run(*device); + return status_p.data().firmware_version <= m[device->get_device_model()]; + } + bool NitrokeyManager::is_AES_supported(const char *user_password) { auto a = get_payload(); strcpyT(a.user_password, user_password); diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index 60fa753..24a83ec 100644 --- a/include/NitrokeyManager.h +++ b/include/NitrokeyManager.h @@ -110,6 +110,10 @@ namespace nitrokey { int get_progress_bar_value(); ~NitrokeyManager(); + bool is_authorization_command_supported(); + + template + void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device); private: NitrokeyManager(); diff --git a/include/device.h b/include/device.h index 3f18921..62c4073 100644 --- a/include/device.h +++ b/include/device.h @@ -12,6 +12,15 @@ namespace nitrokey { namespace device { using namespace std::chrono_literals; + struct EnumClassHash + { + template + std::size_t operator()(T t) const + { + return static_cast(t); + } + }; + enum class DeviceModel{ PRO, STORAGE -- cgit v1.2.3 From c7e33af909a6e9883058685389aea7b5ad5b4dd1 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 10 Nov 2016 18:36:13 +0100 Subject: Mark unused packet variables in TOTP`s GET_CODE Signed-off-by: Szczepan Zalega --- include/stick10_commands_0.8.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h index 9099b3d..5e05405 100644 --- a/include/stick10_commands_0.8.h +++ b/include/stick10_commands_0.8.h @@ -252,9 +252,9 @@ namespace nitrokey { struct CommandPayload { uint8_t temporary_user_password[25]; uint8_t slot_number; - uint64_t challenge; - uint64_t last_totp_time; - uint8_t last_interval; + uint64_t challenge; //@unused + uint64_t last_totp_time; //@unused + uint8_t last_interval; //@unused bool isValid() const { return !(slot_number & 0xF0); } std::string dissect() const { -- cgit v1.2.3 From c51987f47307637beb6a1b75c351f273edda89cf Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 10 Nov 2016 18:40:32 +0100 Subject: Working support for new NK Pro 0.8 authorization-less format Signed-off-by: Szczepan Zalega --- NitrokeyManager.cc | 200 ++++++++++++++++++++++++++++++++++------------ include/NitrokeyManager.h | 16 ++++ 2 files changed, 164 insertions(+), 52 deletions(-) (limited to 'include') diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index b254071..e80f9b5 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -39,7 +39,6 @@ namespace nitrokey{ void NitrokeyManager::authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device){ if (!is_authorization_command_supported()){ Log::instance()("Authorization command not supported, skipping", Loglevel::WARNING); - return; } auto auth = get_payload(); strcpyT(auth.temporary_password, admin_temporary_password); @@ -117,16 +116,25 @@ namespace nitrokey{ } uint32_t 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_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); + + if (is_authorization_command_supported()){ auto gh = get_payload(); 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(gh, user_temporary_password, device); } - auto resp = GetHOTP::CommandTransaction::run(*device, gh); return resp.data().code; + } else { + auto gh = get_payload(); + 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 resp.data().code; + } } @@ -140,26 +148,41 @@ namespace nitrokey{ 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); - auto gt = get_payload(); - 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(gt, user_temporary_password, device); + if (is_authorization_command_supported()){ + auto gt = get_payload(); + 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(gt, user_temporary_password, device); + } + auto resp = GetTOTP::CommandTransaction::run(*device, gt); + return resp.data().code; + } else { + auto gt = get_payload(); + strcpyT(gt.temporary_user_password, user_temporary_password); + gt.slot_number = slot_number; + auto resp = stick10_08::GetTOTP::CommandTransaction::run(*device, gt); + return resp.data().code; } - auto resp = GetTOTP::CommandTransaction::run(*device, gt); - return resp.data().code; + } bool NitrokeyManager::erase_slot(uint8_t slot_number, const char *temporary_password) { + if (is_authorization_command_supported()){ auto p = get_payload(); p.slot_number = slot_number; - authorize_packet(p, temporary_password, device); - auto resp = EraseSlot::CommandTransaction::run(*device,p); + } else { + auto p = get_payload(); + p.slot_number = slot_number; + strcpyT(p.temporary_admin_password, temporary_password); + auto resp = stick10_08::EraseSlot::CommandTransaction::run(*device,p); + } return true; } @@ -191,59 +214,130 @@ namespace nitrokey{ if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); slot_number = get_internal_slot_number_for_hotp(slot_number); - auto payload = get_payload(); - 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); + if (is_authorization_command_supported()){ + write_HOTP_slot_authorize(slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, + token_ID, temporary_password); + } else { + write_HOTP_slot_no_authorize(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_no_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) const { + auto payload = get_payload(); + strcpyT(payload.temporary_admin_password, temporary_password); + auto secret_bin = misc::hex_string_to_byte(secret); + vector_copy(payload.slot_secret, secret_bin); + 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(); + 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); + } + + 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(); + 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::PRO: { payload.slot_counter = hotp_counter; break; } case DeviceModel::STORAGE: { - std::string counter = std::to_string(hotp_counter); + string counter = to_string(hotp_counter); strcpyT(payload.slot_counter_s, counter.c_str()); break; } default: - nitrokey::log::Log::instance()( std::string(__FILE__) + std::to_string(__LINE__) + - std::string(__FUNCTION__) + std::string(" Unhandled device model for HOTP") - , nitrokey::log::Loglevel::DEBUG); + Log::instance()(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; + payload.use_8_digits = use_8_digits; + payload.use_enter = use_enter; + payload.use_tokenID = use_tokenID; - authorize_packet(payload, temporary_password, device); + authorize_packet(payload, temporary_password, device); - auto resp = WriteToHOTPSlot::CommandTransaction::run(*device, payload); - return true; + 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) { - auto payload = get_payload(); if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - slot_number = get_internal_slot_number_for_totp(slot_number); - 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(payload, temporary_password, device); - - auto resp = WriteToTOTPSlot::CommandTransaction::run(*device, payload); - return true; + + if (is_authorization_command_supported()){ + write_TOTP_slot_authorize(slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, + token_ID, temporary_password); + } else { + write_TOTP_slot_no_authorize(slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, + token_ID, temporary_password); + } + + return true; + } + + void NitrokeyManager::write_TOTP_slot_no_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) const { + auto payload = get_payload(); + strcpyT(payload.temporary_admin_password, temporary_password); + auto secret_bin = misc::hex_string_to_byte(secret); + vector_copy(payload.slot_secret, secret_bin); + 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(); + 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); + } + + 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(); + 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(payload, temporary_password, device); + + auto resp = WriteToTOTPSlot::CommandTransaction::run(*device, payload); } const char * NitrokeyManager::get_totp_slot_name(uint8_t slot_number) { @@ -466,16 +560,18 @@ namespace nitrokey{ 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(); + auto p = get_payload(); p.numlock = (uint8_t) numlock; p.capslock = (uint8_t) capslock; p.scrolllock = (uint8_t) scrolllock; p.enable_user_password = (uint8_t) enable_user_password; p.delete_user_password = (uint8_t) delete_user_password; - - authorize_packet(p, admin_temporary_password, device); - - WriteGeneralConfig::CommandTransaction::run(*device, p); + if (is_authorization_command_supported()){ + authorize_packet(p, admin_temporary_password, device); + } else { + strcpyT(p.temporary_admin_password, admin_temporary_password); + } + stick10_08::WriteGeneralConfig::CommandTransaction::run(*device, p); } vector NitrokeyManager::read_config() { diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index 24a83ec..c0064f7 100644 --- a/include/NitrokeyManager.h +++ b/include/NitrokeyManager.h @@ -5,6 +5,7 @@ #include "log.h" #include "device_proto.h" #include "stick10_commands.h" +#include "stick10_commands_0.8.h" #include "stick20_commands.h" #include #include @@ -132,6 +133,21 @@ namespace nitrokey { template void change_PIN_general(char *current_PIN, char *new_PIN); + void 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); + + void write_HOTP_slot_no_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) const; + + void 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); + + void write_TOTP_slot_no_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) const; }; } -- cgit v1.2.3 From 3ab15750995624222fa32927fee7f9b1598ba3bf Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Sat, 12 Nov 2016 11:06:11 +0100 Subject: Move temporary_password to packet end To allow read-only backward compatibility for GET_CODE Signed-off-by: Szczepan Zalega --- include/stick10_commands_0.8.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h index 5e05405..3644c4d 100644 --- a/include/stick10_commands_0.8.h +++ b/include/stick10_commands_0.8.h @@ -201,8 +201,13 @@ namespace nitrokey { class GetHOTP : Command { public: struct CommandPayload { - uint8_t temporary_user_password[25]; uint8_t slot_number; + struct { + uint64_t challenge; //@unused + uint64_t last_totp_time; //@unused + uint8_t last_interval; //@unused + } __packed _unused; + uint8_t temporary_user_password[25]; bool isValid() const { return (slot_number & 0xF0); } std::string dissect() const { @@ -250,11 +255,11 @@ namespace nitrokey { //user auth public: struct CommandPayload { - uint8_t temporary_user_password[25]; uint8_t slot_number; uint64_t challenge; //@unused uint64_t last_totp_time; //@unused uint8_t last_interval; //@unused + uint8_t temporary_user_password[25]; bool isValid() const { return !(slot_number & 0xF0); } std::string dissect() const { -- cgit v1.2.3 From cbccc871329c5522449010ae5007278123508820 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Wed, 16 Nov 2016 18:32:38 +0100 Subject: Use another OTP writing protocol and test it Signed-off-by: Szczepan Zalega --- NitrokeyManager.cc | 67 +++++++++++++++---------- command_id.cc | 3 ++ include/command_id.h | 1 + include/stick10_commands_0.8.h | 111 +++++++++-------------------------------- unittest/constants.py | 2 +- unittest/test3.cc | 111 ++++++++++++++++++++++++++--------------- unittest/test_pro.py | 33 ++++++++++-- 7 files changed, 169 insertions(+), 159 deletions(-) (limited to 'include') 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(); - strcpyT(payload.temporary_admin_password, temporary_password); + auto payload2 = get_payload(); + 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(); + 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(); + 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(); - 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(); - strcpyT(payload.temporary_admin_password, temporary_password); + + auto payload2 = get_payload(); + 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(); + 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(); + 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(); - 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::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 { + class SendOTPData : Command { //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 { + class WriteToOTPSlot : Command { + //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 - CommandTransaction; - }; - - - class WriteToTOTPSlot : Command { - //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 { - 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 - CommandTransaction; - }; - - class GetHOTP : Command { 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(); - 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(); + 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(); + p2 = get_payload(); 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(); + 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(); 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(); - p.enable_user_password = 1; - strcpyT(p.temporary_admin_password, temporary_password); - WriteGeneralConfig::CommandTransaction::run(stick, p); + { + auto p = get_payload(); + p.enable_user_password = 1; + strcpyT(p.temporary_admin_password, temporary_password); + WriteGeneralConfig::CommandTransaction::run(stick, p); + } + + auto p2 = get_payload(); + 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(); + 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(); - 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(); + 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(); - 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(); 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(); - p.enable_user_password = 1; - strcpyT(p.temporary_admin_password, temporary_password); - WriteGeneralConfig::CommandTransaction::run(stick, p); + { + auto p = get_payload(); + p.enable_user_password = 1; + strcpyT(p.temporary_admin_password, temporary_password); + WriteGeneralConfig::CommandTransaction::run(stick, p); + } - auto pw = get_payload(); - 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(); - 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(); + 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(); + 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(); + 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(); 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 + + -- cgit v1.2.3 From 9c2feef240e396648dfb2378f7d2428b0593c9f2 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Fri, 18 Nov 2016 12:52:50 +0100 Subject: Support longer secrets (40 bytes) for NK Pro 0.8 Signed-off-by: Szczepan Zalega --- NitrokeyManager.cc | 29 +++++++++++++++++++++------ include/stick10_commands_0.8.h | 18 ++++++++++++++++- misc.cc | 5 +++-- unittest/test_pro.py | 45 ++++++++++++++++++++++++++++++++++-------- 4 files changed, 80 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index 46c09df..7cc88eb 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -198,6 +198,16 @@ namespace nitrokey{ return erase_slot(slot_number, temporary_password); } + template + void vector_copy_ranged(T& dest, std::vector &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 void vector_copy(T& dest, std::vector &vec){ const size_t d_size = sizeof(dest); @@ -317,13 +327,20 @@ namespace nitrokey{ payload2.setTypeName(); stick10_08::SendOTPData::CommandTransaction::run(*device, payload2); - payload2 = get_payload(); - strcpyT(payload2.temporary_admin_password, temporary_password); - auto secret_bin = misc::hex_string_to_byte(secret); - vector_copy(payload2.data, secret_bin); - payload2.length = strlen((const char *) payload2.data); payload2.setTypeSecret(); - stick10_08::SendOTPData::CommandTransaction::run(*device, payload2); + payload2.id = 0; + auto secret_bin = misc::hex_string_to_byte(secret); + auto remaining_secret_length = secret_bin.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(); strcpyT(payload.temporary_admin_password, temporary_password); diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h index e880c0a..f0e28a6 100644 --- a/include/stick10_commands_0.8.h +++ b/include/stick10_commands_0.8.h @@ -75,7 +75,23 @@ namespace nitrokey { } } __packed; - typedef Transaction + + struct ResponsePayload { + union { + uint8_t data[40]; + } __packed; + + bool isValid() const { return true; } + std::string dissect() const { + std::stringstream ss; + ss << "data:" << std::endl + << ::nitrokey::misc::hexdump((const char *) (&data), sizeof data); + return ss.str(); + } + } __packed; + + + typedef Transaction CommandTransaction; }; diff --git a/misc.cc b/misc.cc index c9d38cb..7a3c199 100644 --- a/misc.cc +++ b/misc.cc @@ -16,7 +16,8 @@ std::vector hex_string_to_byte(const char* hexString){ if (s_size%2!=0 || s_size==0 || s_size>big_string_size){ throw InvalidHexString(0); } - auto data = std::vector(d_size, 0); + auto data = std::vector(); + data.reserve(d_size); char buf[2]; for(int i=0; i hex_string_to_byte(const char* hexString){ } buf[i%2] = c; if (i%2==1){ - data[i/2] = strtoul(buf, NULL, 16) & 0xFF; + data.push_back( strtoul(buf, NULL, 16) & 0xFF ); } } return data; diff --git a/unittest/test_pro.py b/unittest/test_pro.py index 3632ecd..71abfba 100644 --- a/unittest/test_pro.py +++ b/unittest/test_pro.py @@ -501,6 +501,9 @@ def test_get_serial_number(C): @pytest.mark.parametrize("secret", ['000001', '00'*10+'ff', '00'*19+'ff', '000102', '002EF43F51AFA97BA2B46418768123C9E1809A5B' ]) def test_OTP_secret_started_from_null(C, secret): + ''' + NK Pro 0.8+, NK Storage 0.43+ + ''' oath = pytest.importorskip("oath") lib_at = lambda t: oath.hotp(secret, t, format='dec6') PIN_protection = False @@ -522,7 +525,7 @@ def test_OTP_secret_started_from_null(C, secret): assert dev_res == lib_res -@pytest.mark.parametrize("counter", [0, 3, 7, 0xffff] ) +@pytest.mark.parametrize("counter", [0, 3, 7, 0xffff, 0xffffffff, 0xffffffffffffffff] ) def test_HOTP_slots_read_write_counter(C, counter): secret = RFC_SECRET oath = pytest.importorskip("oath") @@ -571,9 +574,13 @@ def test_TOTP_slots_read_write_at_time_period(C, time, period): lib_res += (time, lib_at(time)) assert dev_res == lib_res - -@pytest.mark.parametrize("secret", [RFC_SECRET, 2*RFC_SECRET] ) +@pytest.mark.parametrize("secret", [RFC_SECRET, 2*RFC_SECRET, '12'*10, '12'*30] ) def test_TOTP_secrets(C, secret): + ''' + NK Pro 0.8+, NK Storage 0.44+ + ''' + if is_pro_rtm_07(C) and len(secret)>20*2: #*2 since secret is in hex + pytest.skip("Secret lengths over 20 bytes are not supported by NK Pro 0.7 ") slot_number = 0 time = 0 period = 30 @@ -587,10 +594,8 @@ def test_TOTP_secrets(C, secret): 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, "", + assert C.NK_write_totp_slot(slot_number, 'secret' + str(len(secret)), 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 @@ -598,6 +603,30 @@ def test_TOTP_secrets(C, secret): lib_res += (time, lib_at(time)) assert dev_res == lib_res - - +@pytest.mark.parametrize("secret", [RFC_SECRET, 2*RFC_SECRET, '12'*10, '12'*30] ) +def test_HOTP_secrets(C, secret): + ''' + NK Pro 0.8+, NK Storage 0.44+ + ''' + if is_pro_rtm_07(C) and len(secret)>20*2: #*2 since secret is in hex + pytest.skip("Secret lengths over 20 bytes are not supported by NK Pro 0.7 ") + slot_number = 0 + counter = 0 + oath = pytest.importorskip("oath") + lib_at = lambda t: oath.hotp(secret, counter=t) + 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_write_hotp_slot(slot_number, 'secret' + str(len(secret)), 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 + dev_res += (counter, code_device) + lib_res += (counter, lib_at(counter)) + assert dev_res == lib_res -- cgit v1.2.3 From f615000166177dad7128247d5c99679d9560c510 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Sat, 19 Nov 2016 14:09:40 +0100 Subject: Remove length field from send_otp_data packet Signed-off-by: Szczepan Zalega --- NitrokeyManager.cc | 1 - include/stick10_commands_0.8.h | 2 -- unittest/test3.cc | 6 ------ 3 files changed, 9 deletions(-) (limited to 'include') diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index 7cc88eb..b991af1 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -323,7 +323,6 @@ namespace nitrokey{ auto payload2 = get_payload(); 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); diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h index f0e28a6..f905794 100644 --- a/include/stick10_commands_0.8.h +++ b/include/stick10_commands_0.8.h @@ -51,7 +51,6 @@ namespace nitrokey { uint8_t temporary_admin_password[25]; 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; } @@ -68,7 +67,6 @@ namespace nitrokey { ss << "temporary_admin_password:\t" << temporary_admin_password << 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(); diff --git a/unittest/test3.cc b/unittest/test3.cc index 7b37a60..9049365 100644 --- a/unittest/test3.cc +++ b/unittest/test3.cc @@ -53,13 +53,11 @@ TEST_CASE("write slot", "[pronew]"){ 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(); 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); @@ -138,13 +136,11 @@ TEST_CASE("authorize user HOTP", "[pronew]") { 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(); 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); @@ -191,13 +187,11 @@ TEST_CASE("authorize user TOTP", "[pronew]") { 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(); 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); -- cgit v1.2.3 From 25118d2dea54ce8c6eaec56d722628d0ef484e1c Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Sat, 19 Nov 2016 14:21:23 +0100 Subject: Merge HOTP and TOTP writing commands for 0.8 Signed-off-by: Szczepan Zalega --- NitrokeyManager.cc | 59 ++++++++++++----------------------------------- include/NitrokeyManager.h | 11 ++++----- 2 files changed, 19 insertions(+), 51 deletions(-) (limited to 'include') diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index b991af1..b130f4f 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -223,47 +223,17 @@ namespace nitrokey{ 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); + int internal_slot_number = get_internal_slot_number_for_hotp(slot_number); if (is_authorization_command_supported()){ - write_HOTP_slot_authorize(slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, + 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_HOTP_slot_no_authorize(slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, - token_ID, temporary_password); + 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_no_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) const { - auto payload2 = get_payload(); - 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(); - strcpyT(payload2.temporary_admin_password, temporary_password); - auto secret_bin = misc::hex_string_to_byte(secret); - 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(); - 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 = 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, uint64_t hotp_counter, bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, const char *temporary_password) { @@ -302,23 +272,24 @@ namespace nitrokey{ 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); - slot_number = get_internal_slot_number_for_totp(slot_number); + int internal_slot_number = get_internal_slot_number_for_totp(slot_number); if (is_authorization_command_supported()){ - write_TOTP_slot_authorize(slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, + 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_TOTP_slot_no_authorize(slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, - token_ID, temporary_password); + 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_TOTP_slot_no_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) const { + 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(); strcpyT(payload2.temporary_admin_password, temporary_password); @@ -347,8 +318,8 @@ namespace nitrokey{ payload.use_8_digits = use_8_digits; payload.use_enter = use_enter; payload.use_tokenID = use_tokenID; - payload.slot_counter_or_interval = time_window; - payload.slot_number = slot_number; + payload.slot_counter_or_interval = counter_or_interval; + payload.slot_number = internal_slot_number; stick10_08::WriteToOTPSlot::CommandTransaction::run(*device, payload); } diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index c0064f7..14fa1e5 100644 --- a/include/NitrokeyManager.h +++ b/include/NitrokeyManager.h @@ -137,17 +137,14 @@ namespace nitrokey { bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, const char *temporary_password); - void write_HOTP_slot_no_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) const; - void 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); - void write_TOTP_slot_no_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) const; + void 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; }; } -- cgit v1.2.3 From 9e0c85241234ae607c7eea4bb9f3ee61762b5c0c Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Sat, 26 Nov 2016 15:40:46 +0100 Subject: Update comments Signed-off-by: Szczepan Zalega --- include/stick10_commands_0.8.h | 2 +- unittest/constants.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h index f905794..7de2177 100644 --- a/include/stick10_commands_0.8.h +++ b/include/stick10_commands_0.8.h @@ -49,7 +49,7 @@ namespace nitrokey { public: struct CommandPayload { uint8_t temporary_admin_password[25]; - uint8_t type; //0-secret, 1-name + uint8_t type; //S-secret, N-name uint8_t id; //multiple reports for values longer than 30 bytes uint8_t data[30]; //data, does not need null termination diff --git a/unittest/constants.py b/unittest/constants.py index 3c19a9b..0897b42 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) # '3031323334353637383930...' +RFC_SECRET = to_hex(RFC_SECRET_HR) # '31323334353637383930...' # print( repr((RFC_SECRET, RFC_SECRET_, len(RFC_SECRET))) ) -- cgit v1.2.3 From 740b85c7f935029003e205dcbb5d49842eac1ad6 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Tue, 6 Dec 2016 19:56:14 +0100 Subject: Get major firmware version --- NK_C_API.cc | 7 +++++++ NK_C_API.h | 6 +++++- NitrokeyManager.cc | 16 ++++++++++++++++ include/NitrokeyManager.h | 3 +++ include/stick20_commands.h | 10 ++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/NK_C_API.cc b/NK_C_API.cc index d42840b..e513a3b 100644 --- a/NK_C_API.cc +++ b/NK_C_API.cc @@ -471,6 +471,13 @@ extern int NK_get_progress_bar_value() { }); } +extern int NK_get_major_firmware_version(){ + auto m = NitrokeyManager::instance(); + return get_with_result([&](){ + return m->get_major_firmware_version(); + }); +} + } diff --git a/NK_C_API.h b/NK_C_API.h index a446a62..7f01900 100644 --- a/NK_C_API.h +++ b/NK_C_API.h @@ -324,7 +324,11 @@ extern int NK_erase_password_safe_slot(uint8_t slot_number); */ extern int NK_is_AES_supported(const char *user_password); - +/** + * Get device's major firmware version + * @return 7,8 for Pro and major for Storage + */ +extern int NK_get_major_firmware_version(); diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index b130f4f..da31c8d 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -4,6 +4,7 @@ #include "include/LibraryException.h" #include #include +#include #include "include/misc.h" namespace nitrokey{ @@ -589,9 +590,24 @@ namespace nitrokey{ {DeviceModel::STORAGE, 43}, }); auto status_p = GetStatus::CommandTransaction::run(*device); + //FIXME use different function for checking storage firmware version return status_p.data().firmware_version <= m[device->get_device_model()]; } + int NitrokeyManager::get_major_firmware_version(){ + switch(device->get_device_model()){ + case DeviceModel::PRO:{ + auto status_p = GetStatus::CommandTransaction::run(*device); + return status_p.data().firmware_version; //7 or 8 + } + case DeviceModel::STORAGE:{ + auto status = stick20::GetDeviceStatus::CommandTransaction::run(*device); + return status.data().versionInfo.major; + } + } + return 0; + } + bool NitrokeyManager::is_AES_supported(const char *user_password) { auto a = get_payload(); strcpyT(a.user_password, user_password); diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index 14fa1e5..fd39445 100644 --- a/include/NitrokeyManager.h +++ b/include/NitrokeyManager.h @@ -115,6 +115,8 @@ namespace nitrokey { template void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device); + int get_major_firmware_version(); + private: NitrokeyManager(); @@ -145,6 +147,7 @@ namespace nitrokey { uint64_t counter_or_interval, bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, const char *temporary_password) const; + }; } diff --git a/include/stick20_commands.h b/include/stick20_commands.h index 1af9da3..e6df770 100644 --- a/include/stick20_commands.h +++ b/include/stick20_commands.h @@ -125,7 +125,17 @@ namespace nitrokey { uint16_t MagicNumber_StickConfig_u16; uint8_t ReadWriteFlagUncryptedVolume_u8; uint8_t ReadWriteFlagCryptedVolume_u8; + + union{ uint8_t VersionInfo_au8[4]; + struct { + uint8_t __unused; + uint8_t major; + uint8_t __unused2; + uint8_t minor; + } __packed versionInfo; + }; + uint8_t ReadWriteFlagHiddenVolume_u8; uint8_t FirmwareLocked_u8; uint8_t NewSDCardFound_u8; -- cgit v1.2.3 From eaab841afe29334e5a599b2210f2e8910b0d0b71 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Fri, 9 Dec 2016 11:06:06 +0100 Subject: Use switch to translate command and device statuses instead of array Signed-off-by: Szczepan Zalega --- include/dissect.h | 59 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/include/dissect.h b/include/dissect.h index 59e6e9c..8c975c5 100644 --- a/include/dissect.h +++ b/include/dissect.h @@ -36,44 +36,65 @@ class QueryDissector : semantics::non_constructible { } }; + + + template class ResponseDissector : semantics::non_constructible { public: + static std::string status_translate_device(int status){ + auto enum_status = static_cast(status); + switch (enum_status){ + case stick10::device_status::ok: return "OK"; + case stick10::device_status::busy: return "BUSY"; + case stick10::device_status::error: return "ERROR"; + case stick10::device_status::received_report: return "RECEIVED_REPORT"; + } + return std::string("UNKNOWN: ") + std::to_string(status); + } + + static std::string to_upper(std::string str){ + for (auto & c: str) c = toupper(c); + return str; + } + static std::string status_translate_command(int status){ + auto enum_status = static_cast(status); + switch (enum_status) { +#define p(X) case X: return to_upper(std::string(#X)); + p(stick10::command_status::ok) + p(stick10::command_status::wrong_CRC) + p(stick10::command_status::wrong_slot) + p(stick10::command_status::slot_not_programmed) + p(stick10::command_status::wrong_password) + p(stick10::command_status::not_authorized) + p(stick10::command_status::timestamp_warning) + p(stick10::command_status::no_name_error) + p(stick10::command_status::not_supported) + p(stick10::command_status::unknown_command) + p(stick10::command_status::AES_dec_failed) +#undef p + } + return std::string("UNKNOWN: ") + std::to_string(status); + } + static std::string dissect(const HIDPacket &pod) { std::stringstream out; // FIXME use values from firmware (possibly generate separate // header automatically) - std::string status[4]; - status[0] = " STATUS_READY"; - status[1] = " STATUS_BUSY"; - status[2] = " STATUS_ERROR"; - status[3] = " STATUS_RECEIVED_REPORT"; - std::string cmd[11]; - cmd[0] = " CMD_STATUS_OK"; - cmd[1] = " CMD_STATUS_WRONG_CRC"; - cmd[2] = " CMD_STATUS_WRONG_SLOT"; - cmd[3] = " CMD_STATUS_SLOT_NOT_PROGRAMMED"; - cmd[4] = " CMD_STATUS_WRONG_PASSWORD"; - cmd[5] = " CMD_STATUS_NOT_AUTHORIZED"; - cmd[6] = " CMD_STATUS_TIMESTAMP_WARNING"; - cmd[7] = " CMD_STATUS_NO_NAME_ERROR"; - cmd[8] = " CMD_STATUS_NOT_SUPPORTED"; - cmd[9] = " CMD_STATUS_UNKNOWN_COMMAND"; - cmd[10] = " CMD_STATUS_AES_DEC_FAILED"; out << "Raw HID packet:" << std::endl; out << ::nitrokey::misc::hexdump((const char *)(&pod), sizeof pod); out << "Device status:\t" << pod.device_status + 0 << " " - << status[pod.device_status] << std::endl; + << status_translate_device(pod.device_status) << std::endl; out << "Command ID:\t" << commandid_to_string((CommandID)(pod.command_id)) << " hex: " << std::hex << (int)pod.command_id << std::endl; out << "Last command CRC:\t" << std::hex << std::setw(2) << std::setfill('0') << pod.last_command_crc << std::endl; out << "Last command status:\t" << pod.last_command_status + 0 << " " - << cmd[pod.last_command_status] << std::endl; + << status_translate_command(pod.last_command_status) << std::endl; out << "CRC:\t" << std::hex << std::setw(2) << std::setfill('0') << pod.crc << std::endl; -- cgit v1.2.3 From 58c15291c3c758bc79adc8e65d471b1f5dded136 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Mon, 12 Dec 2016 15:22:11 +0100 Subject: Remove changes to Pro 0.7 stick commands Signed-off-by: Szczepan Zalega --- include/stick10_commands.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'include') diff --git a/include/stick10_commands.h b/include/stick10_commands.h index 5ae2591..f02fd70 100644 --- a/include/stick10_commands.h +++ b/include/stick10_commands.h @@ -48,7 +48,6 @@ class EraseSlot : Command { public: struct CommandPayload { uint8_t slot_number; - uint8_t temporary_admin_password[25]; bool isValid() const { return !(slot_number & 0xF0); } std::string dissect() const { @@ -138,7 +137,6 @@ class WriteToHOTPSlot : Command { }; class WriteToTOTPSlot : Command { - //admin auth public: struct CommandPayload { uint8_t slot_number; @@ -184,7 +182,6 @@ class WriteToTOTPSlot : Command { }; class GetTOTP : Command { - //user auth public: struct CommandPayload { uint8_t slot_number; @@ -615,7 +612,6 @@ class PasswordSafeSendSlotViaHID : Command { // TODO "Device::passwordSafeSendSlotDataViaHID" class WriteGeneralConfig : Command { - //admin auth public: struct CommandPayload { union{ -- cgit v1.2.3 From e26c6da38c674d8ec37e402132dab823bd22bd36 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Mon, 12 Dec 2016 15:48:38 +0100 Subject: Use the rest of the Pro 0.7 commands in 0.8 interface Signed-off-by: Szczepan Zalega --- include/stick10_commands_0.8.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'include') diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h index 7de2177..9594d1e 100644 --- a/include/stick10_commands_0.8.h +++ b/include/stick10_commands_0.8.h @@ -25,6 +25,27 @@ namespace nitrokey { using stick10::UserAuthenticate; using stick10::SetTime; using stick10::GetStatus; + using stick10::BuildAESKey; + using stick10::ChangeAdminPin; + using stick10::ChangeUserPin; + using stick10::EnablePasswordSafe; + using stick10::ErasePasswordSafeSlot; + using stick10::FactoryReset; + using stick10::GetPasswordRetryCount; + using stick10::GetUserPasswordRetryCount; + using stick10::GetPasswordSafeSlotLogin; + using stick10::GetPasswordSafeSlotName; + using stick10::GetPasswordSafeSlotPassword; + using stick10::GetPasswordSafeSlotStatus; + using stick10::GetSlotName; + using stick10::IsAESSupported; + using stick10::LockDevice; + using stick10::PasswordSafeInitKey; + using stick10::PasswordSafeSendSlotViaHID; + using stick10::SetPasswordSafeSlotData; + using stick10::SetPasswordSafeSlotData2; + using stick10::UnlockUserPassword; + using stick10::ReadSlot; class EraseSlot : Command { public: -- cgit v1.2.3