diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/NitrokeyManager.h | 20 | ||||
| -rw-r--r-- | include/command_id.h | 2 | ||||
| -rw-r--r-- | include/device.h | 9 | ||||
| -rw-r--r-- | include/dissect.h | 59 | ||||
| -rw-r--r-- | include/stick10_commands_0.8.h | 312 | ||||
| -rw-r--r-- | include/stick20_commands.h | 10 | 
6 files changed, 393 insertions, 19 deletions
| diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index 60fa753..fd39445 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 <vector>  #include <memory> @@ -110,6 +111,12 @@ namespace nitrokey {          int get_progress_bar_value();          ~NitrokeyManager(); +        bool is_authorization_command_supported(); + +        template <typename S, typename A, typename T> +        void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr<Device> device); +        int get_major_firmware_version(); +      private:          NitrokeyManager(); @@ -128,6 +135,19 @@ namespace nitrokey {          template <typename ProCommand, PasswordKind StoKind>          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_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_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; +      };  } diff --git a/include/command_id.h b/include/command_id.h index a3806f0..346b750 100644 --- a/include/command_id.h +++ b/include/command_id.h @@ -65,6 +65,8 @@ enum class CommandID : uint8_t {    FACTORY_RESET = 0x13,    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/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 <typename T> +        std::size_t operator()(T t) const +        { +          return static_cast<std::size_t>(t); +        } +    }; +  enum class DeviceModel{      PRO,      STORAGE 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 <CommandID id, class HIDPacket>  class ResponseDissector : semantics::non_constructible {   public: +    static std::string status_translate_device(int status){ +      auto enum_status = static_cast<proto::stick10::device_status>(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<proto::stick10::command_status >(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; diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h new file mode 100644 index 0000000..9594d1e --- /dev/null +++ b/include/stick10_commands_0.8.h @@ -0,0 +1,312 @@ +// +// Created by sz on 08.11.16. +// + +#ifndef LIBNITROKEY_STICK10_COMMANDS_0_8_H +#define LIBNITROKEY_STICK10_COMMANDS_0_8_H + +#include <bitset> +#include <iomanip> +#include <string> +#include <sstream> +#include "inttypes.h" +#include "command.h" +#include "device_proto.h" +#include "stick10_commands.h" + +namespace nitrokey { +    namespace proto { + +/* + *	Stick10 protocol definition + */ +        namespace stick10_08 { +            using stick10::FirstAuthenticate; +            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<CommandID::ERASE_SLOT> { +            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<command_id(), struct CommandPayload, struct EmptyPayload> +                    CommandTransaction; +            }; + +            class SendOTPData : Command<CommandID::SEND_OTP_DATA> { +                //admin auth +            public: +                struct CommandPayload { +                    uint8_t temporary_admin_password[25]; +                    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 + +                    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 << "type:\t" << type << std::endl; +                      ss << "id:\t" << (int)id << std::endl; +                      ss << "data:" << std::endl +                         << ::nitrokey::misc::hexdump((const char *) (&data), sizeof data); +                      return ss.str(); +                    } +                } __packed; + + +                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<command_id(), struct CommandPayload, struct ResponsePayload> +                    CommandTransaction; +            }; + +            class WriteToOTPSlot : Command<CommandID::WRITE_TO_SLOT> { +                //admin auth +            public: +                struct CommandPayload { +                    uint8_t temporary_admin_password[25]; +                    uint8_t slot_number; +                    union { +                        uint64_t slot_counter_or_interval; +                        uint8_t slot_counter_s[8]; +                    } __packed; +                    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_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) +                        ss << std::hex << std::setw(2) << std::setfill('0') << (int) i << " "; +                      ss << std::endl; + +                      return ss.str(); +                    } +                } __packed; + +                typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> +                    CommandTransaction; +            }; + +            class GetHOTP : Command<CommandID::GET_CODE> { +            public: +                struct CommandPayload { +                    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 { +                      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<command_id(), struct CommandPayload, struct ResponsePayload> +                    CommandTransaction; +            }; + + +            class GetTOTP : Command<CommandID::GET_CODE> { +                //user auth +            public: +                struct CommandPayload { +                    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 { +                      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; +                      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<command_id(), struct CommandPayload, struct ResponsePayload> +                    CommandTransaction; +            }; + + +            class WriteGeneralConfig : Command<CommandID::WRITE_CONFIG> { +                //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<command_id(), struct CommandPayload, struct EmptyPayload> +                    CommandTransaction; +            }; +        } +    } +} +#endif //LIBNITROKEY_STICK10_COMMANDS_0_8_H 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; | 
