/* * 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 LIBNITROKEY_STICK10_COMMANDS_0_8_H #define LIBNITROKEY_STICK10_COMMANDS_0_8_H #include #include #include #include #include #include "command.h" #include "device_proto.h" #include "stick10_commands.h" #pragma pack (push,1) 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 { 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; hexdump_to_ss(temporary_admin_password); return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class SendOTPData : Command { //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; hexdump_to_ss(temporary_admin_password); ss << "type:\t" << type << std::endl; ss << "id:\t" << (int)id << std::endl; #ifdef LOG_VOLATILE_DATA ss << "data:" << std::endl << ::nitrokey::misc::hexdump((const uint8_t *) (&data), sizeof data); #else ss << " Volatile data not logged" << std::endl; #endif return ss.str(); } } __packed; struct ResponsePayload { union { uint8_t data[40]; } __packed; bool isValid() const { return true; } std::string dissect() const { std::stringstream ss; #ifdef LOG_VOLATILE_DATA ss << "data:" << std::endl << ::nitrokey::misc::hexdump((const uint8_t *) (&data), sizeof data); #else ss << " Volatile data not logged" << std::endl; #endif return ss.str(); } } __packed; typedef Transaction CommandTransaction; }; class WriteToOTPSlot : Command { //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; hexdump_to_ss(temporary_admin_password); 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 uint8_t *) (&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 CommandTransaction; }; class GetHOTP : Command { 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; hexdump_to_ss(temporary_user_password); 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 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; hexdump_to_ss(temporary_user_password); 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 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]; static constexpr uint8_t special_HOTP_slots = 3; bool isValid() const { return numlock < special_HOTP_slots && capslock < special_HOTP_slots && scrolllock < special_HOTP_slots && 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; }; } } } #pragma pack (pop) #endif //LIBNITROKEY_STICK10_COMMANDS_0_8_H