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 --- CMakeLists.txt | 2 + include/command_id.h | 1 + include/stick10_commands.h | 4 + include/stick10_commands_0.8.h | 178 +++++++++++++++++++++++++++++++++++++++++ unittest/test3.cc | 78 ++++++++++++++++++ 5 files changed, 263 insertions(+) create mode 100644 include/stick10_commands_0.8.h create mode 100644 unittest/test3.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index e9cd54f..c324067 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,9 @@ set(SOURCE_FILES unittest/test_C_API.cpp unittest/catch_main.cpp unittest/test2.cc + unittest/test3.cc include/LongOperationInProgressException.h + include/stick10_commands_0.8.h ) add_executable(libnitrokey ${SOURCE_FILES}) \ No newline at end of file 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 diff --git a/unittest/test3.cc b/unittest/test3.cc new file mode 100644 index 0000000..6fab862 --- /dev/null +++ b/unittest/test3.cc @@ -0,0 +1,78 @@ +// +// Created by sz on 08.11.16. +// + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() + +static const char *const default_admin_pin = "12345678"; +static const char *const default_user_pin = "123456"; +const char * temporary_password = "123456789012345678901234"; +const char * RFC_SECRET = "12345678901234567890"; + +#include "catch.hpp" + +#include +#include +#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::log; +using namespace nitrokey::misc; + +void connect_and_setup(Stick10 &stick) { + bool connected = stick.connect(); + REQUIRE(connected == true); + Log::instance().set_loglevel(Loglevel::DEBUG); +} + +void authorize(Stick10 &stick) { + auto authreq = get_payload(); + strcpy((char *) (authreq.card_password), default_admin_pin); + strcpy((char *) (authreq.temporary_password), temporary_password); + FirstAuthenticate::CommandTransaction::run(stick, authreq); +} + +TEST_CASE("write slot", "[pronew]"){ + Stick10 stick; + 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; + stick10_08::WriteToHOTPSlot::CommandTransaction::run(stick, p); + + auto 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); + + auto p3 = get_payload(); + p3.slot_number = 0 + 0x10; + GetHOTP::CommandTransaction::run(stick, p3); + +} + + +TEST_CASE("erase slot", "[pronew]"){ + Stick10 stick; + connect_and_setup(stick); + authorize(stick); + + auto erase_payload = get_payload(); + erase_payload.slot_number = 1 + 0x10; + strcpyT(erase_payload.temporary_admin_password, temporary_password); + stick10_08::EraseSlot::CommandTransaction::run(stick, erase_payload); +} \ No newline at end of file -- cgit v1.2.3