/* * Copyright (c) 2015-2018 Nitrokey UG * * This file is part of libnitrokey. * * libnitrokey is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * libnitrokey is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libnitrokey. If not, see . * * SPDX-License-Identifier: LGPL-3.0 */ #ifndef STICK10_COMMANDS_H #define STICK10_COMMANDS_H #include #include #include #include #include #include "device_proto.h" #include "command.h" #pragma pack (push,1) namespace nitrokey { namespace proto { /* * Stick10 protocol definition */ namespace stick10 { class GetSlotName : public Command { public: // reachable as a typedef in Transaction struct CommandPayload { uint8_t slot_number; bool isValid() const { return slot_number<0x10+3; } std::string dissect() const { std::stringstream ss; ss << "slot_number:\t" << (int)(slot_number) << std::endl; return ss.str(); } } __packed; struct ResponsePayload { uint8_t slot_name[15]; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; print_to_ss_volatile(slot_name); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class EraseSlot : Command { public: struct CommandPayload { uint8_t slot_number; 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 SetTime : Command { public: struct CommandPayload { uint8_t reset; // 0 - get time, 1 - set time uint64_t time; // posix time bool isValid() const { return reset && reset != 1; } std::string dissect() const { std::stringstream ss; ss << "reset:\t" << (int)(reset) << std::endl; ss << "time:\t" << (time) << std::endl; return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class WriteToHOTPSlot : Command { public: struct CommandPayload { uint8_t slot_number; uint8_t slot_name[15]; 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; }; 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 << "slot_number:\t" << (int)(slot_number) << std::endl; print_to_ss_volatile(slot_name); print_to_ss_volatile(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 << "slot_counter:\t[" << (int)slot_counter << "]\t" << ::nitrokey::misc::hexdump((const uint8_t *)(&slot_counter), sizeof slot_counter, false); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class WriteToTOTPSlot : Command { public: struct CommandPayload { uint8_t slot_number; uint8_t slot_name[15]; 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; }; uint16_t slot_interval; bool isValid() const { return !(slot_number & 0xF0); } //TODO check std::string dissect() const { std::stringstream ss; ss << "slot_number:\t" << (int)(slot_number) << std::endl; print_to_ss_volatile(slot_name); print_to_ss_volatile(slot_secret); ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << 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 << "slot_interval:\t" << (int)slot_interval << std::endl; return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class GetTOTP : Command { public: struct CommandPayload { uint8_t slot_number; uint64_t challenge; uint64_t last_totp_time; uint8_t last_interval; 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; }; class GetHOTP : Command { public: struct CommandPayload { uint8_t slot_number; 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; 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 ReadSlot : Command { public: struct CommandPayload { uint8_t slot_number; 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; struct ResponsePayload { uint8_t slot_name[15]; 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; }; union{ uint64_t slot_counter; uint8_t slot_counter_s[8]; } __packed; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; print_to_ss_volatile(slot_name); 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 << "slot_counter:\t[" << (int)slot_counter << "]\t" << ::nitrokey::misc::hexdump((const uint8_t *)(&slot_counter), sizeof slot_counter, false); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class GetStatus : Command { public: struct ResponsePayload { union { uint16_t firmware_version; struct { uint8_t minor; uint8_t major; } firmware_version_st; }; union{ uint8_t card_serial[4]; uint32_t card_serial_u32; } __packed; union { uint8_t general_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; /* unused */ } __packed; } __packed; static constexpr uint8_t special_HOTP_slots = 2; bool isValid() const { return numlock < special_HOTP_slots && capslock < special_HOTP_slots && scrolllock < special_HOTP_slots && enable_user_password < 2; } std::string get_card_serial_hex() const { return nitrokey::misc::toHex(card_serial_u32); } std::string dissect() const { std::stringstream ss; ss << "firmware_version:\t" << "[" << firmware_version << "]" << "\t" << ::nitrokey::misc::hexdump( (const uint8_t *)(&firmware_version), sizeof firmware_version, false); ss << "card_serial_u32:\t" << std::hex << card_serial_u32 << std::endl; ss << "card_serial:\t" << ::nitrokey::misc::hexdump((const uint8_t *)(card_serial), sizeof card_serial, false); ss << "general_config:\t" << ::nitrokey::misc::hexdump((const uint8_t *)(general_config), sizeof general_config, false); 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; }; class GetPasswordRetryCount : Command { public: struct ResponsePayload { uint8_t password_retry_count; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; ss << " password_retry_count\t" << (int)password_retry_count << std::endl; return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class GetUserPasswordRetryCount : Command { public: struct ResponsePayload { uint8_t password_retry_count; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; ss << " password_retry_count\t" << (int)password_retry_count << std::endl; return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; template void write_array(T &ss, Q (&arr)[N]){ for (int i=0; i { public: struct ResponsePayload { uint8_t password_safe_status[PWS_SLOT_COUNT]; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; ss << "password_safe_status\t"; write_array(ss, password_safe_status); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class GetPasswordSafeSlotName : Command { public: struct CommandPayload { uint8_t slot_number; 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; struct ResponsePayload { uint8_t slot_name[PWS_SLOTNAME_LENGTH]; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; print_to_ss_volatile(slot_name); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class GetPasswordSafeSlotPassword : Command { public: struct CommandPayload { uint8_t slot_number; 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; struct ResponsePayload { uint8_t slot_password[PWS_PASSWORD_LENGTH]; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; print_to_ss_volatile(slot_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class GetPasswordSafeSlotLogin : Command { public: struct CommandPayload { uint8_t slot_number; 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; struct ResponsePayload { uint8_t slot_login[PWS_LOGINNAME_LENGTH]; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; print_to_ss_volatile(slot_login); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class SetPasswordSafeSlotData : Command { public: struct CommandPayload { uint8_t slot_number; uint8_t slot_name[PWS_SLOTNAME_LENGTH]; uint8_t slot_password[PWS_PASSWORD_LENGTH]; bool isValid() const { return !(slot_number & 0xF0); } std::string dissect() const { std::stringstream ss; ss << " slot_number\t" << (int)slot_number << std::endl; print_to_ss_volatile(slot_name); print_to_ss_volatile(slot_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class SetPasswordSafeSlotData2 : Command { public: struct CommandPayload { uint8_t slot_number; uint8_t slot_login_name[PWS_LOGINNAME_LENGTH]; bool isValid() const { return !(slot_number & 0xF0); } std::string dissect() const { std::stringstream ss; ss << " slot_number\t" << (int)slot_number << std::endl; print_to_ss_volatile(slot_login_name); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class ErasePasswordSafeSlot : Command { public: struct CommandPayload { uint8_t slot_number; 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 EnablePasswordSafe : Command { public: struct CommandPayload { uint8_t user_password[30]; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; print_to_ss_volatile(user_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class PasswordSafeInitKey : Command { /** * never used in Nitrokey App */ public: typedef Transaction CommandTransaction; }; class PasswordSafeSendSlotViaHID : Command { /** * never used in Nitrokey App */ public: struct CommandPayload { uint8_t slot_number; uint8_t slot_kind; bool isValid() const { return !(slot_number & 0xF0); } } __packed; typedef Transaction CommandTransaction; }; // TODO "Device::passwordSafeSendSlotDataViaHID" class WriteGeneralConfig : Command { 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; }; }; bool isValid() const { return numlock < 2 && capslock < 2 && scrolllock < 2 && enable_user_password < 2; } 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; }; class FirstAuthenticate : Command { public: struct CommandPayload { uint8_t card_password[25]; uint8_t temporary_password[25]; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; print_to_ss_volatile(card_password); hexdump_to_ss(temporary_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class UserAuthenticate : Command { public: struct CommandPayload { uint8_t card_password[25]; uint8_t temporary_password[25]; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; print_to_ss_volatile(card_password); hexdump_to_ss(temporary_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class Authorize : Command { public: struct CommandPayload { uint32_t crc_to_authorize; uint8_t temporary_password[25]; std::string dissect() const { std::stringstream ss; ss << " crc_to_authorize:\t" << std::hex << std::setw(2) << std::setfill('0') << crc_to_authorize<< std::endl; hexdump_to_ss(temporary_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class UserAuthorize : Command { public: struct CommandPayload { uint32_t crc_to_authorize; uint8_t temporary_password[25]; std::string dissect() const { std::stringstream ss; ss << " crc_to_authorize:\t" << crc_to_authorize<< std::endl; hexdump_to_ss(temporary_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class UnlockUserPassword : Command { public: struct CommandPayload { uint8_t admin_password[25]; uint8_t user_new_password[25]; std::string dissect() const { std::stringstream ss; print_to_ss_volatile(admin_password); print_to_ss_volatile(user_new_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class ChangeUserPin : Command { public: struct CommandPayload { uint8_t old_pin[25]; uint8_t new_pin[25]; std::string dissect() const { std::stringstream ss; print_to_ss_volatile(old_pin); print_to_ss_volatile(new_pin); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class IsAESSupported : Command { public: struct CommandPayload { uint8_t user_password[20]; std::string dissect() const { std::stringstream ss; print_to_ss_volatile(user_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class ChangeAdminPin : Command { public: struct CommandPayload { uint8_t old_pin[25]; uint8_t new_pin[25]; std::string dissect() const { std::stringstream ss; print_to_ss_volatile(old_pin); print_to_ss_volatile(new_pin); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class LockDevice : Command { public: typedef Transaction CommandTransaction; }; class FactoryReset : Command { public: struct CommandPayload { uint8_t admin_password[20]; std::string dissect() const { std::stringstream ss; print_to_ss_volatile(admin_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class BuildAESKey : Command { public: struct CommandPayload { uint8_t admin_password[20]; std::string dissect() const { std::stringstream ss; print_to_ss_volatile(admin_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; } } } #pragma pack (pop) #endif