From 15dc909b1bd2621b64c7fd58a7cf55a4778876cf Mon Sep 17 00:00:00 2001 From: David Seifert Date: Sun, 11 Mar 2018 11:31:57 +0100 Subject: Make unbundling easier --- CMakeLists.txt | 34 +- NK_C_API.cc | 6 +- NitrokeyManager.cc | 8 +- device.cc | 6 +- include/CommandFailedException.h | 76 --- include/DeviceCommunicationExceptions.h | 73 -- include/LibraryException.h | 118 ---- include/LongOperationInProgressException.h | 45 -- include/NitrokeyManager.h | 283 -------- include/command.h | 112 ---- include/command_id.h | 152 ----- include/cxx_semantics.h | 44 -- include/device.h | 169 ----- include/device_proto.h | 491 -------------- include/dissect.h | 145 ---- include/hidapi/hidapi.h | 391 ----------- include/log.h | 108 --- include/misc.h | 94 --- include/stick10_commands.h | 884 ------------------------- include/stick10_commands_0.8.h | 344 ---------- include/stick20_commands.h | 388 ----------- libnitrokey/CommandFailedException.h | 76 +++ libnitrokey/DeviceCommunicationExceptions.h | 73 ++ libnitrokey/LibraryException.h | 118 ++++ libnitrokey/LongOperationInProgressException.h | 45 ++ libnitrokey/NitrokeyManager.h | 283 ++++++++ libnitrokey/command.h | 112 ++++ libnitrokey/command_id.h | 152 +++++ libnitrokey/cxx_semantics.h | 44 ++ libnitrokey/device.h | 169 +++++ libnitrokey/device_proto.h | 491 ++++++++++++++ libnitrokey/dissect.h | 145 ++++ libnitrokey/hidapi/hidapi.h | 391 +++++++++++ libnitrokey/log.h | 108 +++ libnitrokey/misc.h | 94 +++ libnitrokey/stick10_commands.h | 884 +++++++++++++++++++++++++ libnitrokey/stick10_commands_0.8.h | 344 ++++++++++ libnitrokey/stick20_commands.h | 388 +++++++++++ 38 files changed, 3944 insertions(+), 3944 deletions(-) delete mode 100644 include/CommandFailedException.h delete mode 100644 include/DeviceCommunicationExceptions.h delete mode 100644 include/LibraryException.h delete mode 100644 include/LongOperationInProgressException.h delete mode 100644 include/NitrokeyManager.h delete mode 100644 include/command.h delete mode 100644 include/command_id.h delete mode 100644 include/cxx_semantics.h delete mode 100644 include/device.h delete mode 100644 include/device_proto.h delete mode 100644 include/dissect.h delete mode 100644 include/hidapi/hidapi.h delete mode 100644 include/log.h delete mode 100644 include/misc.h delete mode 100644 include/stick10_commands.h delete mode 100644 include/stick10_commands_0.8.h delete mode 100644 include/stick20_commands.h create mode 100644 libnitrokey/CommandFailedException.h create mode 100644 libnitrokey/DeviceCommunicationExceptions.h create mode 100644 libnitrokey/LibraryException.h create mode 100644 libnitrokey/LongOperationInProgressException.h create mode 100644 libnitrokey/NitrokeyManager.h create mode 100644 libnitrokey/command.h create mode 100644 libnitrokey/command_id.h create mode 100644 libnitrokey/cxx_semantics.h create mode 100644 libnitrokey/device.h create mode 100644 libnitrokey/device_proto.h create mode 100644 libnitrokey/dissect.h create mode 100644 libnitrokey/hidapi/hidapi.h create mode 100644 libnitrokey/log.h create mode 100644 libnitrokey/misc.h create mode 100644 libnitrokey/stick10_commands.h create mode 100644 libnitrokey/stick10_commands_0.8.h create mode 100644 libnitrokey/stick20_commands.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6037393..43250b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,23 +42,23 @@ ENDIF() MESSAGE("${PROJECT_NAME}: Build type: ${CMAKE_BUILD_TYPE}") include_directories(hidapi) -include_directories(include) +include_directories(libnitrokey) set(SOURCE_FILES - include/command.h - include/command_id.h - include/cxx_semantics.h - include/device.h - include/device_proto.h - include/dissect.h - include/log.h - include/misc.h - include/NitrokeyManager.h - include/stick10_commands.h - include/stick20_commands.h - include/CommandFailedException.h - include/LibraryException.h - include/LongOperationInProgressException.h - include/stick10_commands_0.8.h + libnitrokey/command.h + libnitrokey/command_id.h + libnitrokey/cxx_semantics.h + libnitrokey/device.h + libnitrokey/device_proto.h + libnitrokey/dissect.h + libnitrokey/log.h + libnitrokey/misc.h + libnitrokey/NitrokeyManager.h + libnitrokey/stick10_commands.h + libnitrokey/stick20_commands.h + libnitrokey/CommandFailedException.h + libnitrokey/LibraryException.h + libnitrokey/LongOperationInProgressException.h + libnitrokey/stick10_commands_0.8.h command_id.cc device.cc log.cc @@ -115,7 +115,7 @@ IF (LOG_VOLATILE_DATA) ENDIF() -file(GLOB LIB_INCLUDES "include/*.h" "NK_C_API.h") +file(GLOB LIB_INCLUDES "libnitrokey/*.h" "NK_C_API.h") install (FILES ${LIB_INCLUDES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) install (TARGETS nitrokey DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/NK_C_API.cc b/NK_C_API.cc index dde150b..64355f5 100644 --- a/NK_C_API.cc +++ b/NK_C_API.cc @@ -21,10 +21,10 @@ #include "NK_C_API.h" #include -#include "include/NitrokeyManager.h" +#include "libnitrokey/NitrokeyManager.h" #include -#include "include/LibraryException.h" -#include "include/cxx_semantics.h" +#include "libnitrokey/LibraryException.h" +#include "libnitrokey/cxx_semantics.h" #ifdef _MSC_VER #ifdef _WIN32 diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index e5f10df..db0c0a9 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -21,14 +21,14 @@ #include #include -#include "include/NitrokeyManager.h" -#include "include/LibraryException.h" +#include "libnitrokey/NitrokeyManager.h" +#include "libnitrokey/LibraryException.h" #include #include #include -#include "include/misc.h" +#include "libnitrokey/misc.h" #include -#include "include/cxx_semantics.h" +#include "libnitrokey/cxx_semantics.h" #include #include diff --git a/device.cc b/device.cc index da5345b..da54e33 100644 --- a/device.cc +++ b/device.cc @@ -25,9 +25,9 @@ #include #include #include "hidapi/hidapi.h" -#include "include/misc.h" -#include "include/device.h" -#include "include/log.h" +#include "libnitrokey/misc.h" +#include "libnitrokey/device.h" +#include "libnitrokey/log.h" #include #include "DeviceCommunicationExceptions.h" #include "device.h" diff --git a/include/CommandFailedException.h b/include/CommandFailedException.h deleted file mode 100644 index 32bd6b7..0000000 --- a/include/CommandFailedException.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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_COMMANDFAILEDEXCEPTION_H -#define LIBNITROKEY_COMMANDFAILEDEXCEPTION_H - -#include -#include -#include "log.h" -#include "command_id.h" - -using cs = nitrokey::proto::stick10::command_status; -using cs2 = nitrokey::proto::stick20::device_status; - -class CommandFailedException : public std::exception { -public: - const uint8_t last_command_id; - const uint8_t last_command_status; - - CommandFailedException(uint8_t last_command_id, uint8_t last_command_status) : - last_command_id(last_command_id), - last_command_status(last_command_status){ - LOG(std::string("CommandFailedException, status: ")+ std::to_string(last_command_status), nitrokey::log::Loglevel::DEBUG); - } - - virtual const char *what() const throw() { - return "Command execution has failed on device"; - } - - - bool reason_timestamp_warning() const throw(){ - return last_command_status == static_cast(cs::timestamp_warning); - } - - bool reason_AES_not_initialized() const throw(){ - return last_command_status == static_cast(cs::AES_dec_failed); - } - - bool reason_not_authorized() const throw(){ - return last_command_status == static_cast(cs::not_authorized); - } - - bool reason_slot_not_programmed() const throw(){ - return last_command_status == static_cast(cs::slot_not_programmed); - } - - bool reason_wrong_password() const throw(){ - return last_command_status == static_cast(cs::wrong_password); - } - - bool reason_smartcard_busy() const throw(){ - return last_command_status == static_cast(cs2::smartcard_error); - } - -}; - - -#endif //LIBNITROKEY_COMMANDFAILEDEXCEPTION_H diff --git a/include/DeviceCommunicationExceptions.h b/include/DeviceCommunicationExceptions.h deleted file mode 100644 index f710d0b..0000000 --- a/include/DeviceCommunicationExceptions.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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_DEVICECOMMUNICATIONEXCEPTIONS_H -#define LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H - -#include -#include -#include -#include - - -class DeviceCommunicationException: public std::runtime_error -{ - std::string message; - static std::atomic_int occurred; -public: - DeviceCommunicationException(std::string _msg): std::runtime_error(_msg), message(_msg){ - ++occurred; - } - uint8_t getType() const {return 1;}; -// virtual const char* what() const throw() override { -// return message.c_str(); -// } - static bool has_occurred(){ return occurred > 0; }; - static void reset_occurred_flag(){ occurred = 0; }; -}; - -class DeviceNotConnected: public DeviceCommunicationException { -public: - DeviceNotConnected(std::string msg) : DeviceCommunicationException(msg){} - uint8_t getType() const {return 2;}; -}; - -class DeviceSendingFailure: public DeviceCommunicationException { -public: - DeviceSendingFailure(std::string msg) : DeviceCommunicationException(msg){} - uint8_t getType() const {return 3;}; -}; - -class DeviceReceivingFailure: public DeviceCommunicationException { -public: - DeviceReceivingFailure(std::string msg) : DeviceCommunicationException(msg){} - uint8_t getType() const {return 4;}; -}; - -class InvalidCRCReceived: public DeviceReceivingFailure { -public: - InvalidCRCReceived(std::string msg) : DeviceReceivingFailure(msg){} - uint8_t getType() const {return 5;}; -}; - - -#endif //LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H diff --git a/include/LibraryException.h b/include/LibraryException.h deleted file mode 100644 index 3b9d177..0000000 --- a/include/LibraryException.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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_LIBRARYEXCEPTION_H -#define LIBNITROKEY_LIBRARYEXCEPTION_H - -#include -#include -#include -#include "log.h" - -class LibraryException: std::exception { -public: - virtual uint8_t exception_id()= 0; -}; - -class TargetBufferSmallerThanSource: public LibraryException { -public: - virtual uint8_t exception_id() override { - return 203; - } - -public: - size_t source_size; - size_t target_size; - - TargetBufferSmallerThanSource( - size_t source_size, size_t target_size - ) : source_size(source_size), target_size(target_size) {} - - virtual const char *what() const throw() override { - std::string s = " "; - auto ts = [](size_t x){ return std::to_string(x); }; - std::string msg = std::string("Target buffer size is smaller than source: [source size, buffer size]") - +s+ ts(source_size) +s+ ts(target_size); - return msg.c_str(); - } - -}; - -class InvalidHexString : public LibraryException { -public: - virtual uint8_t exception_id() override { - return 202; - } - -public: - uint8_t invalid_char; - - InvalidHexString (uint8_t invalid_char) : invalid_char( invalid_char) {} - - virtual const char *what() const throw() override { - return "Invalid character in hex string"; - } - -}; - -class InvalidSlotException : public LibraryException { -public: - virtual uint8_t exception_id() override { - return 201; - } - -public: - uint8_t slot_selected; - - InvalidSlotException(uint8_t slot_selected) : slot_selected(slot_selected) {} - - virtual const char *what() const throw() override { - return "Wrong slot selected"; - } - -}; - - - -class TooLongStringException : public LibraryException { -public: - virtual uint8_t exception_id() override { - return 200; - } - - std::size_t size_source; - std::size_t size_destination; - std::string message; - - TooLongStringException(size_t size_source, size_t size_destination, const std::string &message = "") : size_source( - size_source), size_destination(size_destination), message(message) { - LOG(std::string("TooLongStringException, size diff: ")+ std::to_string(size_source-size_destination), nitrokey::log::Loglevel::DEBUG); - - } - - virtual const char *what() const throw() override { - //TODO add sizes and message data to final message - return "Too long string has been supplied as an argument"; - } - -}; - -#endif //LIBNITROKEY_LIBRARYEXCEPTION_H diff --git a/include/LongOperationInProgressException.h b/include/LongOperationInProgressException.h deleted file mode 100644 index 865d6b5..0000000 --- a/include/LongOperationInProgressException.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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_LONGOPERATIONINPROGRESSEXCEPTION_H -#define LIBNITROKEY_LONGOPERATIONINPROGRESSEXCEPTION_H - -#include "CommandFailedException.h" - -class LongOperationInProgressException : public CommandFailedException { - -public: - unsigned char progress_bar_value; - - LongOperationInProgressException( - unsigned char _command_id, uint8_t last_command_status, unsigned char _progress_bar_value) - : CommandFailedException(_command_id, last_command_status), progress_bar_value(_progress_bar_value){ - LOG( - std::string("LongOperationInProgressException, progress bar status: ")+ - std::to_string(progress_bar_value), nitrokey::log::Loglevel::DEBUG); - } - virtual const char *what() const throw() { - return "Device returned busy status with long operation in progress"; - } -}; - - -#endif //LIBNITROKEY_LONGOPERATIONINPROGRESSEXCEPTION_H diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h deleted file mode 100644 index ca58d24..0000000 --- a/include/NitrokeyManager.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * 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_NITROKEYMANAGER_H -#define LIBNITROKEY_NITROKEYMANAGER_H - -#include "device.h" -#include "log.h" -#include "device_proto.h" -#include "stick10_commands.h" -#include "stick10_commands_0.8.h" -#include "stick20_commands.h" -#include -#include -#include - -namespace nitrokey { - using namespace nitrokey::device; - using namespace std; - using namespace nitrokey::proto::stick10; - using namespace nitrokey::proto::stick20; - using namespace nitrokey::proto; - using namespace nitrokey::log; - - -#ifdef __WIN32 -char * strndup(const char* str, size_t maxlen); -#endif - - class NitrokeyManager { - public: - static shared_ptr instance(); - - bool first_authenticate(const char *pin, const char *temporary_password); - bool write_HOTP_slot(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); - bool 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); - string get_HOTP_code(uint8_t slot_number, const char *user_temporary_password); - string get_TOTP_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, - uint8_t last_interval, - const char *user_temporary_password); - string get_TOTP_code(uint8_t slot_number, const char *user_temporary_password); - stick10::ReadSlot::ResponsePayload get_TOTP_slot_data(const uint8_t slot_number); - stick10::ReadSlot::ResponsePayload get_HOTP_slot_data(const uint8_t slot_number); - - bool set_time(uint64_t time); - bool get_time(uint64_t time = 0); - bool erase_totp_slot(uint8_t slot_number, const char *temporary_password); - bool erase_hotp_slot(uint8_t slot_number, const char *temporary_password); - std::vector list_devices(); - std::vector list_devices_by_cpuID(); - - /** - * Connect to the device using unique smartcard:datacard id. - * Needs list_device_by_cpuID() run first - * @param id Current ID of the target device - * @return true on success, false on failure - */ - bool connect_with_ID(const std::string id); - bool connect_with_path (std::string path); - bool connect(const char *device_model); - bool connect(); - bool disconnect(); - bool is_connected() throw() ; - bool could_current_device_be_enumerated(); - bool set_default_commands_delay(int delay); - - DeviceModel get_connected_device_model() const; - void set_debug(bool state); - stick10::GetStatus::ResponsePayload get_status(); - string get_status_as_string(); - string get_serial_number(); - - const char * get_totp_slot_name(uint8_t slot_number); - const char * get_hotp_slot_name(uint8_t slot_number); - - void change_user_PIN(const char *current_PIN, const char *new_PIN); - void change_admin_PIN(const char *current_PIN, const char *new_PIN); - - void enable_password_safe(const char *user_pin); - - vector get_password_safe_slot_status(); - - uint8_t get_admin_retry_count(); - uint8_t get_user_retry_count(); - - void lock_device(); - - const char *get_password_safe_slot_name(uint8_t slot_number); - const char *get_password_safe_slot_password(uint8_t slot_number); - const char *get_password_safe_slot_login(uint8_t slot_number); - - void - write_password_safe_slot(uint8_t slot_number, const char *slot_name, const char *slot_login, - const char *slot_password); - - void erase_password_safe_slot(uint8_t slot_number); - - void user_authenticate(const char *user_password, const char *temporary_password); - - void factory_reset(const char *admin_password); - - void build_aes_key(const char *admin_password); - - void unlock_user_password(const char *admin_password, const char *new_user_password); - - void write_config(uint8_t numlock, uint8_t capslock, uint8_t scrolllock, bool enable_user_password, - bool delete_user_password, const char *admin_temporary_password); - - vector read_config(); - - bool is_AES_supported(const char *user_password); - - void unlock_encrypted_volume(const char *user_password); - void lock_encrypted_volume(); - - void unlock_hidden_volume(const char *hidden_volume_password); - void lock_hidden_volume(); - - /** - * Sets unencrypted volume read-only. - * Works until v0.48 (incl. v0.50), where User PIN was sufficient - * Does nothing otherwise. - * @param user_pin User PIN - */ - void set_unencrypted_read_only(const char *user_pin); - - /** - * Sets unencrypted volume read-only. - * Works from v0.49 (except v0.50) accepts Admin PIN - * Does nothing otherwise. - * @param admin_pin Admin PIN - */ - void set_unencrypted_read_only_admin(const char *admin_pin); - - /** - * Sets unencrypted volume read-write. - * Works until v0.48 (incl. v0.50), where User PIN was sufficient - * Does nothing otherwise. - * @param user_pin User PIN - */ - void set_unencrypted_read_write(const char *user_pin); - - /** - * Sets unencrypted volume read-write. - * Works from v0.49 (except v0.50) accepts Admin PIN - * Does nothing otherwise. - * @param admin_pin Admin PIN - */ - void set_unencrypted_read_write_admin(const char *admin_pin); - - void export_firmware(const char *admin_pin); - void enable_firmware_update(const char *firmware_pin); - - void clear_new_sd_card_warning(const char *admin_pin); - - void fill_SD_card_with_random_data(const char *admin_pin); - - uint8_t get_SD_card_size(); - - void change_update_password(const char *current_update_password, const char *new_update_password); - - void create_hidden_volume(uint8_t slot_nr, uint8_t start_percent, uint8_t end_percent, - const char *hidden_volume_password); - - void send_startup(uint64_t seconds_from_epoch); - - const char * get_status_storage_as_string(); - stick20::DeviceConfigurationResponsePacket::ResponsePayload get_status_storage(); - - const char *get_SD_usage_data_as_string(); - std::pair get_SD_usage_data(); - - - int get_progress_bar_value(); - - ~NitrokeyManager(); - bool is_authorization_command_supported(); - bool is_320_OTP_secret_supported(); - - - template - void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device); - int get_minor_firmware_version(); - - explicit NitrokeyManager(); - void set_log_function(std::function log_function); - private: - - static shared_ptr _instance; - std::shared_ptr device; - std::string current_device_id; - public: - const string get_current_device_id() const; - - private: - std::unordered_map > connected_devices; - std::unordered_map > connected_devices_byID; - - - stick10::ReadSlot::ResponsePayload get_OTP_slot_data(const uint8_t slot_number); - bool is_valid_hotp_slot_number(uint8_t slot_number) const; - bool is_valid_totp_slot_number(uint8_t slot_number) const; - bool is_valid_password_safe_slot_number(uint8_t slot_number) const; - uint8_t get_internal_slot_number_for_hotp(uint8_t slot_number) const; - uint8_t get_internal_slot_number_for_totp(uint8_t slot_number) const; - bool erase_slot(uint8_t slot_number, const char *temporary_password); - const char * get_slot_name(uint8_t slot_number); - - template - void change_PIN_general(const char *current_PIN, const 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; - bool _disconnect_no_lock(); - - public: - bool set_current_device_speed(int retry_delay, int send_receive_delay); - void set_loglevel(Loglevel loglevel); - - void set_loglevel(int loglevel); - - /** - * Sets encrypted volume read-only. - * Supported from future versions of Storage. - * @param admin_pin Admin PIN - */ - void set_encrypted_volume_read_only(const char *admin_pin); - - /** - * Sets encrypted volume read-write. - * Supported from future versions of Storage. - * @param admin_pin Admin PIN - */ - void set_encrypted_volume_read_write(const char *admin_pin); - - int get_major_firmware_version(); - - bool is_smartcard_in_use(); - - /** - * Function to determine unencrypted volume PIN type - * @param minor_firmware_version - * @return Returns true, if set unencrypted volume ro/rw pin type is User, false otherwise. - */ - bool set_unencrypted_volume_rorw_pin_type_user(); - }; -} - - - -#endif //LIBNITROKEY_NITROKEYMANAGER_H diff --git a/include/command.h b/include/command.h deleted file mode 100644 index 6852bf0..0000000 --- a/include/command.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 COMMAND_H -#define COMMAND_H -#include -#include "command_id.h" -#include "cxx_semantics.h" - -#define print_to_ss(x) ( ss << " " << (#x) <<":\t" << (x) << std::endl ); -#ifdef LOG_VOLATILE_DATA -#define print_to_ss_volatile(x) print_to_ss(x); -#else -#define print_to_ss_volatile(x) ( ss << " " << (#x) <<":\t" << "***********" << std::endl ); -#endif -#define hexdump_to_ss(x) (ss << #x":\n"\ - << ::nitrokey::misc::hexdump((const uint8_t *) (&x), sizeof x, false)); - -namespace nitrokey { - namespace proto { - - template - class Command : semantics::non_constructible { - public: - constexpr static CommandID command_id() { return cmd_id; } - - template - std::string dissect(const T &) { - return std::string("Payload dissection is unavailable"); - } - }; - -namespace stick20{ - enum class PasswordKind : uint8_t { - User = 'P', - Admin = 'A', - AdminPrefixed - }; - - template - class PasswordCommand : public Command { - constexpr static CommandID _command_id() { return cmd_id; } - public: - struct CommandPayload { - uint8_t kind; - uint8_t password[password_length]; - - std::string dissect() const { - std::stringstream ss; - print_to_ss( kind ); - print_to_ss_volatile(password); - return ss.str(); - } - void set_kind_admin() { - kind = (uint8_t) 'A'; - } - void set_kind_admin_prefixed() { - kind = (uint8_t) 'P'; - } - void set_kind_user() { - kind = (uint8_t) 'P'; - } - - void set_defaults(){ - set_kind(Tpassword_kind); - } - - void set_kind(PasswordKind password_kind){ - switch (password_kind){ - case PasswordKind::Admin: - set_kind_admin(); - break; - case PasswordKind::User: - set_kind_user(); - break; - case PasswordKind::AdminPrefixed: - set_kind_admin_prefixed(); - break; - } - }; - - } __packed; - - //typedef Transaction::command_id(), struct CommandPayload, struct EmptyPayload> - // CommandTransaction; - using CommandTransaction = Transaction; - //using CommandTransaction = Transaction<_command_id(), CommandPayload, EmptyPayload>; - - }; - } - } -} - -#endif diff --git a/include/command_id.h b/include/command_id.h deleted file mode 100644 index 1092ea9..0000000 --- a/include/command_id.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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 COMMAND_ID_H -#define COMMAND_ID_H -#include - -namespace nitrokey { -namespace proto { - namespace stick20 { - enum class device_status : uint8_t { - idle = 0, - ok, - busy, - wrong_password, - busy_progressbar, - password_matrix_ready, - no_user_password_unlock, // FIXME: translate on receive to command status error (fix in firmware?) - smartcard_error, - security_bit_active - }; - const int CMD_START_VALUE = 0x20; - const int CMD_END_VALUE = 0x60; - } - namespace stick10 { - enum class command_status : uint8_t { - ok = 0, - wrong_CRC, - wrong_slot, - slot_not_programmed, - wrong_password = 4, - not_authorized, - timestamp_warning, - no_name_error, - not_supported, - unknown_command, - AES_dec_failed - }; - enum class device_status : uint8_t { - ok = 0, - busy = 1, - error, - received_report, - }; - } - - -enum class CommandID : uint8_t { - GET_STATUS = 0x00, - WRITE_TO_SLOT = 0x01, - READ_SLOT_NAME = 0x02, - READ_SLOT = 0x03, - GET_CODE = 0x04, - WRITE_CONFIG = 0x05, - ERASE_SLOT = 0x06, - FIRST_AUTHENTICATE = 0x07, - AUTHORIZE = 0x08, - GET_PASSWORD_RETRY_COUNT = 0x09, - CLEAR_WARNING = 0x0A, - SET_TIME = 0x0B, - TEST_COUNTER = 0x0C, - TEST_TIME = 0x0D, - USER_AUTHENTICATE = 0x0E, - GET_USER_PASSWORD_RETRY_COUNT = 0x0F, - USER_AUTHORIZE = 0x10, - UNLOCK_USER_PASSWORD = 0x11, - LOCK_DEVICE = 0x12, - 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, - ENABLE_HIDDEN_CRYPTED_PARI = 0x20 + 2, - DISABLE_HIDDEN_CRYPTED_PARI = 0x20 + 3, - ENABLE_FIRMWARE_UPDATE = 0x20 + 4, //enables update mode - EXPORT_FIRMWARE_TO_FILE = 0x20 + 5, - GENERATE_NEW_KEYS = 0x20 + 6, - FILL_SD_CARD_WITH_RANDOM_CHARS = 0x20 + 7, - - WRITE_STATUS_DATA = 0x20 + 8, //@unused - ENABLE_READONLY_UNCRYPTED_LUN = 0x20 + 9, - ENABLE_READWRITE_UNCRYPTED_LUN = 0x20 + 10, - - SEND_PASSWORD_MATRIX = 0x20 + 11, //@unused - SEND_PASSWORD_MATRIX_PINDATA = 0x20 + 12, //@unused - SEND_PASSWORD_MATRIX_SETUP = 0x20 + 13, //@unused - - GET_DEVICE_STATUS = 0x20 + 14, - SEND_DEVICE_STATUS = 0x20 + 15, - - SEND_HIDDEN_VOLUME_PASSWORD = 0x20 + 16, //@unused - SEND_HIDDEN_VOLUME_SETUP = 0x20 + 17, - SEND_PASSWORD = 0x20 + 18, - SEND_NEW_PASSWORD = 0x20 + 19, - CLEAR_NEW_SD_CARD_FOUND = 0x20 + 20, - - SEND_STARTUP = 0x20 + 21, - SEND_CLEAR_STICK_KEYS_NOT_INITIATED = 0x20 + 22, - SEND_LOCK_STICK_HARDWARE = 0x20 + 23, //locks firmware upgrade - - PRODUCTION_TEST = 0x20 + 24, - SEND_DEBUG_DATA = 0x20 + 25, //@unused - - CHANGE_UPDATE_PIN = 0x20 + 26, - - //added in v0.48.5 - ENABLE_ADMIN_READONLY_UNCRYPTED_LUN = 0x20 + 28, - ENABLE_ADMIN_READWRITE_UNCRYPTED_LUN = 0x20 + 29, - ENABLE_ADMIN_READONLY_ENCRYPTED_LUN = 0x20 + 30, - ENABLE_ADMIN_READWRITE_ENCRYPTED_LUN = 0x20 + 31, - CHECK_SMARTCARD_USAGE = 0x20 + 32, - - GET_PW_SAFE_SLOT_STATUS = 0x60, - GET_PW_SAFE_SLOT_NAME = 0x61, - GET_PW_SAFE_SLOT_PASSWORD = 0x62, - GET_PW_SAFE_SLOT_LOGINNAME = 0x63, - SET_PW_SAFE_SLOT_DATA_1 = 0x64, - SET_PW_SAFE_SLOT_DATA_2 = 0x65, - PW_SAFE_ERASE_SLOT = 0x66, - PW_SAFE_ENABLE = 0x67, - PW_SAFE_INIT_KEY = 0x68, //@unused - PW_SAFE_SEND_DATA = 0x69, //@unused - SD_CARD_HIGH_WATERMARK = 0x70, - DETECT_SC_AES = 0x6a, - NEW_AES_KEY = 0x6b -}; - -const char *commandid_to_string(CommandID id); -} -} -#endif diff --git a/include/cxx_semantics.h b/include/cxx_semantics.h deleted file mode 100644 index 36ed142..0000000 --- a/include/cxx_semantics.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 CXX_SEMANTICS_H -#define CXX_SEMANTICS_H - -#ifndef _MSC_VER -#define __packed __attribute__((__packed__)) -#else -#define __packed -#endif - -#ifdef _MSC_VER -#define strdup _strdup -#endif - -/* - * There's no need to include Boost for a simple subset this project needs. - */ -namespace semantics { -class non_constructible { - non_constructible() {} -}; -} - -#endif diff --git a/include/device.h b/include/device.h deleted file mode 100644 index f6d2380..0000000 --- a/include/device.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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 DEVICE_H -#define DEVICE_H -#include -#include "hidapi/hidapi.h" -#include -#include -#include - -#define HID_REPORT_SIZE 65 - -#include - -namespace nitrokey { -namespace device { - using namespace std::chrono_literals; - using std::chrono::milliseconds; - - struct EnumClassHash - { - template - std::size_t operator()(T t) const - { - return static_cast(t); - } - }; - -enum class DeviceModel{ - PRO, - STORAGE -}; - -#include - -class Device { - -public: - - struct ErrorCounters{ - using cnt = std::atomic_int; - cnt wrong_CRC; - cnt CRC_other_than_awaited; - cnt busy; - cnt total_retries; - cnt sending_error; - cnt receiving_error; - cnt total_comm_runs; - cnt successful_storage_commands; - cnt command_successful_recv; - cnt recv_executed; - cnt sends_executed; - cnt busy_progressbar; - cnt command_result_not_equal_0_recv; - cnt communication_successful; - cnt low_level_reconnect; - std::string get_as_string(); - - } m_counters = {}; - - - Device(const uint16_t vid, const uint16_t pid, const DeviceModel model, - const milliseconds send_receive_delay, const int retry_receiving_count, - const milliseconds retry_timeout); - - virtual ~Device(); - - // lack of device is not actually an error, - // so it doesn't throw - virtual bool connect(); - virtual bool disconnect(); - - /* - * Sends packet of HID_REPORT_SIZE. - */ - virtual int send(const void *packet); - - /* - * Gets packet of HID_REPORT_SIZE. - * Can sleep. See below. - */ - virtual int recv(void *packet); - - /*** - * Returns true if some device is visible by OS with given VID and PID - * whether the device is connected through HID API or not. - * @return true if visible by OS - */ - bool could_be_enumerated(); - std::vector enumerate(); - - - void show_stats(); -// ErrorCounters get_stats(){ return m_counters; } - int get_retry_receiving_count() const { return m_retry_receiving_count; }; - int get_retry_sending_count() const { return m_retry_sending_count; }; - std::chrono::milliseconds get_retry_timeout() const { return m_retry_timeout; }; - std::chrono::milliseconds get_send_receive_delay() const {return m_send_receive_delay;} - - int get_last_command_status() {int a = std::atomic_exchange(&last_command_status, static_cast(0)); return a;}; - void set_last_command_status(uint8_t _err) { last_command_status = _err;} ; - bool last_command_sucessfull() const {return last_command_status == 0;}; - DeviceModel get_device_model() const {return m_model;} - void set_receiving_delay(std::chrono::milliseconds delay); - void set_retry_delay(std::chrono::milliseconds delay); - static void set_default_device_speed(int delay); - void setDefaultDelay(); - void set_path(const std::string path); - - - private: - std::atomic last_command_status; - void _reconnect(); - bool _connect(); - bool _disconnect(); - -protected: - const uint16_t m_vid; - const uint16_t m_pid; - const DeviceModel m_model; - - /* - * While the project uses Signal11 portable HIDAPI - * library, there's no way of doing it asynchronously, - * hence polling. - */ - const int m_retry_sending_count; - const int m_retry_receiving_count; - std::chrono::milliseconds m_retry_timeout; - std::chrono::milliseconds m_send_receive_delay; - std::atomicmp_devhandle; - std::string m_path; - - static std::atomic_int instances_count; - static std::chrono::milliseconds default_delay ; -}; - -class Stick10 : public Device { - public: - Stick10(); - -}; - -class Stick20 : public Device { - public: - Stick20(); -}; -} -} -#endif diff --git a/include/device_proto.h b/include/device_proto.h deleted file mode 100644 index 45a6c16..0000000 --- a/include/device_proto.h +++ /dev/null @@ -1,491 +0,0 @@ -/* - * 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 DEVICE_PROTO_H -#define DEVICE_PROTO_H - -#include -#include -#include -#include -#include -// a local version for compatibility with Windows -#include -#include "cxx_semantics.h" -#include "device.h" -#include "misc.h" -#include "log.h" -#include "command_id.h" -#include "dissect.h" -#include "CommandFailedException.h" -#include "LongOperationInProgressException.h" - -#define STICK20_UPDATE_MODE_VID 0x03EB -#define STICK20_UPDATE_MODE_PID 0x2FF1 - -#define PAYLOAD_SIZE 53 -#define PWS_SLOT_COUNT 16 -#define PWS_SLOTNAME_LENGTH 11 -#define PWS_PASSWORD_LENGTH 20 -#define PWS_LOGINNAME_LENGTH 32 - -#define PWS_SEND_PASSWORD 0 -#define PWS_SEND_LOGINNAME 1 -#define PWS_SEND_TAB 2 -#define PWS_SEND_CR 3 - -#include -#include "DeviceCommunicationExceptions.h" -#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) - -namespace nitrokey { - namespace proto { - extern std::mutex send_receive_mtx; - - -/* - * POD types for HID proto commands - * Instances are meant to be __packed. - * - * TODO (future) support for Big Endian - */ -#pragma pack (push,1) -/* - * Every packet is a USB HID report (check USB spec) - */ - template - struct HIDReport { - uint8_t _zero; - CommandID command_id; // uint8_t - union { - uint8_t _padding[HID_REPORT_SIZE - 6]; - Payload payload; - } __packed; - uint32_t crc; - - // POD types can't have non-default constructors - // used in Transaction<>::run() - void initialize() { - bzero(this, sizeof *this); - command_id = cmd_id; - } - - uint32_t calculate_CRC() const { - // w/o leading zero, a part of each HID packet - // w/o 4-byte crc - return misc::stm_crc32((const uint8_t *) (this) + 1, - (size_t) (HID_REPORT_SIZE - 5)); - } - - void update_CRC() { crc = calculate_CRC(); } - - bool isCRCcorrect() const { return crc == calculate_CRC(); } - - bool isValid() const { - return true; - // return !_zero && payload.isValid() && isCRCcorrect(); - } - - operator std::string() const { - // Packet type is known upfront in normal operation. - // Can't be used to dissect random packets. - return QueryDissector::dissect(*this); - } - } __packed; - -/* - * Response payload (the parametrized type inside struct HIDReport) - * - * command_id member in incoming HIDReport structure carries the command - * type last used. - */ - namespace DeviceResponseConstants{ - //magic numbers from firmware - static constexpr auto storage_status_absolute_address = 21; - static constexpr auto storage_data_absolute_address = storage_status_absolute_address + 5; - static constexpr auto header_size = 8; //from _zero to last_command_status inclusive - static constexpr auto footer_size = 4; //crc - static constexpr auto wrapping_size = header_size + footer_size; - } - - template - struct DeviceResponse { - static constexpr auto storage_status_padding_size = - DeviceResponseConstants::storage_status_absolute_address - DeviceResponseConstants::header_size; - - uint8_t _zero; - uint8_t device_status; - uint8_t command_id; // originally last_command_type - uint32_t last_command_crc; - uint8_t last_command_status; - - union { - uint8_t _padding[HID_REPORT_SIZE - DeviceResponseConstants::wrapping_size]; - ResponsePayload payload; - struct { - uint8_t _storage_status_padding[storage_status_padding_size]; - uint8_t command_counter; - uint8_t command_id; - uint8_t device_status; //@see stick20::device_status - uint8_t progress_bar_value; - } __packed storage_status; - } __packed; - - uint32_t crc; - - void initialize() { bzero(this, sizeof *this); } - - uint32_t calculate_CRC() const { - // w/o leading zero, a part of each HID packet - // w/o 4-byte crc - return misc::stm_crc32((const uint8_t *) (this) + 1, - (size_t) (HID_REPORT_SIZE - 5)); - } - - void update_CRC() { crc = calculate_CRC(); } - bool isCRCcorrect() const { return crc == calculate_CRC(); } - bool isValid() const { - // return !_zero && payload.isValid() && isCRCcorrect() && - // command_id == (uint8_t)(cmd_id); - return crc != 0; - } - - operator std::string() const { - return ResponseDissector::dissect(*this); - } - } __packed; - - struct EmptyPayload { - bool isValid() const { return true; } - - std::string dissect() const { return std::string("Empty Payload."); } - } __packed; - - template - class ClearingProxy { - public: - ClearingProxy(command_packet &p) { - packet = p; - bzero(&p, sizeof(p)); - } - - ~ClearingProxy() { - bzero(&packet, sizeof(packet)); - } - - response_payload &data() { - return packet.payload; - } - - command_packet packet; - }; - - template - class Transaction : semantics::non_constructible { - public: - // Types declared in command class scope can't be reached from there. - typedef command_payload CommandPayload; - typedef response_payload ResponsePayload; - - - typedef struct HIDReport OutgoingPacket; - typedef struct DeviceResponse ResponsePacket; -#pragma pack (pop) - - static_assert(std::is_pod::value, - "outgoingpacket must be a pod type"); - static_assert(std::is_pod::value, - "ResponsePacket must be a POD type"); - static_assert(sizeof(OutgoingPacket) == HID_REPORT_SIZE, - "OutgoingPacket type is not the right size"); - static_assert(sizeof(ResponsePacket) == HID_REPORT_SIZE, - "ResponsePacket type is not the right size"); - - static uint32_t getCRC( - const command_payload &payload) { - OutgoingPacket outp; - outp.initialize(); - outp.payload = payload; - outp.update_CRC(); - return outp.crc; - } - - template - static void clear_packet(T &st) { - bzero(&st, sizeof(st)); - } - - static ClearingProxy run(std::shared_ptr dev, - const command_payload &payload) { - using namespace ::nitrokey::device; - using namespace ::nitrokey::log; - using namespace std::chrono_literals; - - std::lock_guard guard(send_receive_mtx); - - LOG(__FUNCTION__, Loglevel::DEBUG_L2); - - if (dev == nullptr){ - LOG(std::string("Throw: Device not initialized"), Loglevel::DEBUG_L1); - throw DeviceNotConnected("Device not initialized"); - } - dev->m_counters.total_comm_runs++; - - int status; - OutgoingPacket outp; - ResponsePacket resp; - - // POD types can't have non-default constructors - outp.initialize(); - resp.initialize(); - - outp.payload = payload; - outp.update_CRC(); - - LOG("-------------------", Loglevel::DEBUG); - LOG("Outgoing HID packet:", Loglevel::DEBUG); - LOG(static_cast(outp), Loglevel::DEBUG); - LOG(std::string("=> ") + std::string(commandid_to_string(static_cast(outp.command_id))), Loglevel::DEBUG_L1); - - - if (!outp.isValid()) { - LOG(std::string("Throw: Invalid outgoing packet"), Loglevel::DEBUG_L1); - throw DeviceSendingFailure("Invalid outgoing packet"); - } - - bool successful_communication = false; - int receiving_retry_counter = 0; - int sending_retry_counter = dev->get_retry_sending_count(); - while (sending_retry_counter-- > 0) { - dev->m_counters.sends_executed++; - status = dev->send(&outp); - if (status <= 0){ - //FIXME early disconnection not yet working properly -// LOG("Encountered communication error, disconnecting device", Loglevel::DEBUG_L2); -// dev->disconnect(); - dev->m_counters.sending_error++; - LOG(std::string("Throw: Device error while sending command "), Loglevel::DEBUG_L1); - throw DeviceSendingFailure( - std::string("Device error while sending command ") + - std::to_string(status)); - } - - std::this_thread::sleep_for(dev->get_send_receive_delay()); - - // FIXME make checks done in device:recv here - receiving_retry_counter = dev->get_retry_receiving_count(); - int busy_counter = 0; - auto retry_timeout = dev->get_retry_timeout(); - while (receiving_retry_counter-- > 0) { - dev->m_counters.recv_executed++; - status = dev->recv(&resp); - - if (dev->get_device_model() == DeviceModel::STORAGE && - resp.command_id >= stick20::CMD_START_VALUE && - resp.command_id < stick20::CMD_END_VALUE ) { - LOG(std::string("Detected storage device cmd, status: ") + - std::to_string(resp.storage_status.device_status), Loglevel::DEBUG_L2); - - resp.last_command_status = static_cast(stick10::command_status::ok); - switch (static_cast(resp.storage_status.device_status)) { - case stick20::device_status::idle : - case stick20::device_status::ok: - resp.device_status = static_cast(stick10::device_status::ok); - break; - case stick20::device_status::busy: - case stick20::device_status::busy_progressbar: //TODO this will be modified later for getting progressbar status - resp.device_status = static_cast(stick10::device_status::busy); - break; - case stick20::device_status::wrong_password: - resp.last_command_status = static_cast(stick10::command_status::wrong_password); - resp.device_status = static_cast(stick10::device_status::ok); - break; - case stick20::device_status::no_user_password_unlock: - resp.last_command_status = static_cast(stick10::command_status::AES_dec_failed); - resp.device_status = static_cast(stick10::device_status::ok); - break; - default: - LOG(std::string("Unknown storage device status, cannot translate: ") + - std::to_string(resp.storage_status.device_status), Loglevel::DEBUG); - resp.device_status = resp.storage_status.device_status; - break; - }; - } - - //Some of the commands return wrong CRC, for now skip checking it (TODO list and report) - //if (resp.device_status == 0 && resp.last_command_crc == outp.crc && resp.isCRCcorrect()) break; - auto CRC_equal_awaited = true; // resp.last_command_crc == outp.crc; - if (resp.device_status == static_cast(stick10::device_status::ok) && - CRC_equal_awaited && resp.isValid()){ - successful_communication = true; - break; - } - if (resp.device_status == static_cast(stick10::device_status::busy)) { - dev->m_counters.busy++; - - if (busy_counter++<10) { - receiving_retry_counter++; - LOG("Status busy, not decreasing receiving_retry_counter counter: " + - std::to_string(receiving_retry_counter), Loglevel::DEBUG_L2); - } else { - retry_timeout *= 2; - retry_timeout = std::min(retry_timeout, 300ms); - busy_counter = 0; - LOG("Status busy, decreasing receiving_retry_counter counter: " + - std::to_string(receiving_retry_counter) + ", current delay:" - + std::to_string(retry_timeout.count()), Loglevel::DEBUG); - LOG(std::string("Busy retry: status ") - + std::to_string(resp.storage_status.device_status) - + ", " - + std::to_string(retry_timeout.count()) - + "ms, counter " - + std::to_string(receiving_retry_counter) - + ", progress: " - + std::to_string(resp.storage_status.progress_bar_value) - , Loglevel::DEBUG_L1); - } - } - if (resp.device_status == static_cast(stick10::device_status::busy) && - static_cast(resp.storage_status.device_status) - == stick20::device_status::busy_progressbar){ - successful_communication = true; - break; - } - LOG(std::string("Retry status - dev status, awaited cmd crc, correct packet CRC: ") - + std::to_string(resp.device_status) + - " " + std::to_string(CRC_equal_awaited) + - " " + std::to_string(resp.isCRCcorrect()), Loglevel::DEBUG_L2); - - if (!resp.isCRCcorrect()) dev->m_counters.wrong_CRC++; - if (!CRC_equal_awaited) dev->m_counters.CRC_other_than_awaited++; - - - LOG( - "Device is not ready or received packet's last CRC is not equal to sent CRC packet, retrying...", - Loglevel::DEBUG_L2); - LOG("Invalid incoming HID packet:", Loglevel::DEBUG_L2); - LOG(static_cast(resp), Loglevel::DEBUG_L2); - dev->m_counters.total_retries++; - LOG(".", Loglevel::DEBUG_L1); - std::this_thread::sleep_for(retry_timeout); - continue; - } - if (successful_communication) break; - LOG(std::string("Resending (outer loop) "), Loglevel::DEBUG_L2); - LOG(std::string("sending_retry_counter count: ") + std::to_string(sending_retry_counter), - Loglevel::DEBUG); - } - - if(resp.last_command_crc != outp.crc){ - LOG(std::string("Accepting response with CRC other than expected ") - + "Command ID: " + std::to_string(resp.command_id) + " " + - commandid_to_string(static_cast(resp.command_id)) + " " - + "Reported by response and expected: " + std::to_string(resp.last_command_crc) + "!=" + std::to_string(outp.crc), - Loglevel::WARNING - ); - } - - dev->set_last_command_status(resp.last_command_status); // FIXME should be handled on device.recv - - clear_packet(outp); - - - if (status <= 0) { - dev->m_counters.receiving_error++; - LOG(std::string("Throw: Device error while executing command "), Loglevel::DEBUG_L1); - throw DeviceReceivingFailure( //FIXME replace with CriticalErrorException - std::string("Device error while executing command ") + - std::to_string(status)); - } - - LOG(std::string("<= ") + - std::string( - commandid_to_string(static_cast(resp.command_id)) - + std::string(" ") - + std::to_string(resp.device_status) - + std::string(" ") - + std::to_string(resp.storage_status.device_status) -// + std::to_string( status_translate_command(resp.storage_status.device_status)) - ), Loglevel::DEBUG_L1); - - LOG("Incoming HID packet:", Loglevel::DEBUG); - LOG(static_cast(resp), Loglevel::DEBUG); - if (dev->get_retry_receiving_count() - receiving_retry_counter > 2) { - LOG(std::string("Packet received with receiving_retry_counter count: ") + - std::to_string(receiving_retry_counter), - Loglevel::DEBUG_L1); - } - - if (resp.device_status == static_cast(stick10::device_status::busy) && - static_cast(resp.storage_status.device_status) - == stick20::device_status::busy_progressbar){ - dev->m_counters.busy_progressbar++; - LOG(std::string("Throw: Long operation in progress exception"), Loglevel::DEBUG_L1); - throw LongOperationInProgressException( - resp.command_id, resp.device_status, resp.storage_status.progress_bar_value); - } - - if (!resp.isValid()) { - LOG(std::string("Throw: Invalid incoming packet"), Loglevel::DEBUG_L1); - throw InvalidCRCReceived("Invalid incoming packet"); - } - if (receiving_retry_counter <= 0){ - LOG(std::string("Throw: \"Maximum receiving_retry_counter count reached for receiving response from the device!\"" - + std::to_string(receiving_retry_counter)), Loglevel::DEBUG_L1); - throw DeviceReceivingFailure( - "Maximum receiving_retry_counter count reached for receiving response from the device!"); - } - dev->m_counters.communication_successful++; - - if (resp.last_command_status != static_cast(stick10::command_status::ok)){ - dev->m_counters.command_result_not_equal_0_recv++; - LOG(std::string("Throw: CommandFailedException ") + std::to_string(resp.last_command_status), Loglevel::DEBUG_L1); - throw CommandFailedException(resp.command_id, resp.last_command_status); - } - - dev->m_counters.command_successful_recv++; - - if (dev->get_device_model() == DeviceModel::STORAGE && - resp.command_id >= stick20::CMD_START_VALUE && - resp.command_id < stick20::CMD_END_VALUE ) { - dev->m_counters.successful_storage_commands++; - } - - if (!resp.isCRCcorrect()) - LOG(std::string("Accepting response from device with invalid CRC. ") - + "Command ID: " + std::to_string(resp.command_id) + " " + - commandid_to_string(static_cast(resp.command_id)) + " " - + "Reported and calculated: " + std::to_string(resp.crc) + "!=" + std::to_string(resp.calculate_CRC()), - Loglevel::WARNING - ); - - // See: DeviceResponse - return resp; - } - - static ClearingProxy run(std::shared_ptr dev) { - command_payload empty_payload; - return run(dev, empty_payload); - } - }; - } -} -#endif diff --git a/include/dissect.h b/include/dissect.h deleted file mode 100644 index 690b5b7..0000000 --- a/include/dissect.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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 - */ - -/* - * Protocol packet dissection - */ -#ifndef DISSECT_H -#define DISSECT_H -#include -#include -#include -#include "misc.h" -#include "cxx_semantics.h" -#include "command_id.h" -#include "device_proto.h" - -namespace nitrokey { -namespace proto { - -template -class QueryDissector : semantics::non_constructible { - public: - static std::string dissect(const HIDPacket &pod) { - std::stringstream out; - -#ifdef LOG_VOLATILE_DATA - out << "Raw HID packet:" << std::endl; - out << ::nitrokey::misc::hexdump((const uint8_t *)(&pod), sizeof pod); -#endif - - out << "Contents:" << std::endl; - out << "Command ID:\t" << commandid_to_string((CommandID)(pod.command_id)) - << std::endl; - out << "CRC:\t" - << std::hex << std::setw(2) << std::setfill('0') - << pod.crc << std::endl; - - out << "Payload:" << std::endl; - out << pod.payload.dissect(); - return out.str(); - } -}; - - - - -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) - -#ifdef LOG_VOLATILE_DATA - out << "Raw HID packet:" << std::endl; - out << ::nitrokey::misc::hexdump((const uint8_t *)(&pod), sizeof pod); -#endif - - out << "Device status:\t" << pod.device_status + 0 << " " - << 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 << " " - << status_translate_command(pod.last_command_status) << std::endl; - out << "CRC:\t" - << std::hex << std::setw(2) << std::setfill('0') - << pod.crc << std::endl; - if((int)pod.command_id == pod.storage_status.command_id){ - out << "Storage stick status (where applicable):" << std::endl; -#define d(x) out << " "#x": \t"<< std::hex << std::setw(2) \ - << std::setfill('0')<< static_cast(x) << std::endl; - d(pod.storage_status.command_counter); - d(pod.storage_status.command_id); - d(pod.storage_status.device_status); - d(pod.storage_status.progress_bar_value); -#undef d - } - - out << "Payload:" << std::endl; - out << pod.payload.dissect(); - return out.str(); - } -}; -} -} - -#endif diff --git a/include/hidapi/hidapi.h b/include/hidapi/hidapi.h deleted file mode 100644 index e5bc2dc..0000000 --- a/include/hidapi/hidapi.h +++ /dev/null @@ -1,391 +0,0 @@ -/******************************************************* - HIDAPI - Multi-Platform library for - communication with HID devices. - - Alan Ott - Signal 11 Software - - 8/22/2009 - - Copyright 2009, All Rights Reserved. - - At the discretion of the user of this library, - this software may be licensed under the terms of the - GNU General Public License v3, a BSD-Style license, or the - original HIDAPI license as outlined in the LICENSE.txt, - LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt - files located at the root of the source distribution. - These files may also be found in the public source - code repository located at: - http://github.com/signal11/hidapi . -********************************************************/ - -/** @file - * @defgroup API hidapi API - */ - -#ifndef HIDAPI_H__ -#define HIDAPI_H__ - -#include - -#ifdef _WIN32 - #define HID_API_EXPORT __declspec(dllexport) - #define HID_API_CALL -#else - #define HID_API_EXPORT /**< API export macro */ - #define HID_API_CALL /**< API call macro */ -#endif - -#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ - -#ifdef __cplusplus -extern "C" { -#endif - struct hid_device_; - typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ - - /** hidapi info structure */ - struct hid_device_info { - /** Platform-specific device path */ - char *path; - /** Device Vendor ID */ - unsigned short vendor_id; - /** Device Product ID */ - unsigned short product_id; - /** Serial Number */ - wchar_t *serial_number; - /** Device Release Number in binary-coded decimal, - also known as Device Version Number */ - unsigned short release_number; - /** Manufacturer String */ - wchar_t *manufacturer_string; - /** Product string */ - wchar_t *product_string; - /** Usage Page for this Device/Interface - (Windows/Mac only). */ - unsigned short usage_page; - /** Usage for this Device/Interface - (Windows/Mac only).*/ - unsigned short usage; - /** The USB interface which this logical device - represents. Valid on both Linux implementations - in all cases, and valid on the Windows implementation - only if the device contains more than one interface. */ - int interface_number; - - /** Pointer to the next device */ - struct hid_device_info *next; - }; - - - /** @brief Initialize the HIDAPI library. - - This function initializes the HIDAPI library. Calling it is not - strictly necessary, as it will be called automatically by - hid_enumerate() and any of the hid_open_*() functions if it is - needed. This function should be called at the beginning of - execution however, if there is a chance of HIDAPI handles - being opened by different threads simultaneously. - - @ingroup API - - @returns - This function returns 0 on success and -1 on error. - */ - int HID_API_EXPORT HID_API_CALL hid_init(void); - - /** @brief Finalize the HIDAPI library. - - This function frees all of the static data associated with - HIDAPI. It should be called at the end of execution to avoid - memory leaks. - - @ingroup API - - @returns - This function returns 0 on success and -1 on error. - */ - int HID_API_EXPORT HID_API_CALL hid_exit(void); - - /** @brief Enumerate the HID Devices. - - This function returns a linked list of all the HID devices - attached to the system which match vendor_id and product_id. - If @p vendor_id is set to 0 then any vendor matches. - If @p product_id is set to 0 then any product matches. - If @p vendor_id and @p product_id are both set to 0, then - all HID devices will be returned. - - @ingroup API - @param vendor_id The Vendor ID (VID) of the types of device - to open. - @param product_id The Product ID (PID) of the types of - device to open. - - @returns - This function returns a pointer to a linked list of type - struct #hid_device, containing information about the HID devices - attached to the system, or NULL in the case of failure. Free - this linked list by calling hid_free_enumeration(). - */ - struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); - - /** @brief Free an enumeration Linked List - - This function frees a linked list created by hid_enumerate(). - - @ingroup API - @param devs Pointer to a list of struct_device returned from - hid_enumerate(). - */ - void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); - - /** @brief Open a HID device using a Vendor ID (VID), Product ID - (PID) and optionally a serial number. - - If @p serial_number is NULL, the first device with the - specified VID and PID is opened. - - @ingroup API - @param vendor_id The Vendor ID (VID) of the device to open. - @param product_id The Product ID (PID) of the device to open. - @param serial_number The Serial Number of the device to open - (Optionally NULL). - - @returns - This function returns a pointer to a #hid_device object on - success or NULL on failure. - */ - HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); - - /** @brief Open a HID device by its path name. - - The path name be determined by calling hid_enumerate(), or a - platform-specific path name can be used (eg: /dev/hidraw0 on - Linux). - - @ingroup API - @param path The path name of the device to open - - @returns - This function returns a pointer to a #hid_device object on - success or NULL on failure. - */ - HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); - - /** @brief Write an Output report to a HID device. - - The first byte of @p data[] must contain the Report ID. For - devices which only support a single report, this must be set - to 0x0. The remaining bytes contain the report data. Since - the Report ID is mandatory, calls to hid_write() will always - contain one more byte than the report contains. For example, - if a hid report is 16 bytes long, 17 bytes must be passed to - hid_write(), the Report ID (or 0x0, for devices with a - single report), followed by the report data (16 bytes). In - this example, the length passed in would be 17. - - hid_write() will send the data on the first OUT endpoint, if - one exists. If it does not, it will send the data through - the Control Endpoint (Endpoint 0). - - @ingroup API - @param device A device handle returned from hid_open(). - @param data The data to send, including the report number as - the first byte. - @param length The length in bytes of the data to send. - - @returns - This function returns the actual number of bytes written and - -1 on error. - */ - int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); - - /** @brief Read an Input report from a HID device with timeout. - - Input reports are returned - to the host through the INTERRUPT IN endpoint. The first byte will - contain the Report number if the device uses numbered reports. - - @ingroup API - @param device A device handle returned from hid_open(). - @param data A buffer to put the read data into. - @param length The number of bytes to read. For devices with - multiple reports, make sure to read an extra byte for - the report number. - @param milliseconds timeout in milliseconds or -1 for blocking wait. - - @returns - This function returns the actual number of bytes read and - -1 on error. If no packet was available to be read within - the timeout period, this function returns 0. - */ - int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); - - /** @brief Read an Input report from a HID device. - - Input reports are returned - to the host through the INTERRUPT IN endpoint. The first byte will - contain the Report number if the device uses numbered reports. - - @ingroup API - @param device A device handle returned from hid_open(). - @param data A buffer to put the read data into. - @param length The number of bytes to read. For devices with - multiple reports, make sure to read an extra byte for - the report number. - - @returns - This function returns the actual number of bytes read and - -1 on error. If no packet was available to be read and - the handle is in non-blocking mode, this function returns 0. - */ - int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); - - /** @brief Set the device handle to be non-blocking. - - In non-blocking mode calls to hid_read() will return - immediately with a value of 0 if there is no data to be - read. In blocking mode, hid_read() will wait (block) until - there is data to read before returning. - - Nonblocking can be turned on and off at any time. - - @ingroup API - @param device A device handle returned from hid_open(). - @param nonblock enable or not the nonblocking reads - - 1 to enable nonblocking - - 0 to disable nonblocking. - - @returns - This function returns 0 on success and -1 on error. - */ - int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); - - /** @brief Send a Feature report to the device. - - Feature reports are sent over the Control endpoint as a - Set_Report transfer. The first byte of @p data[] must - contain the Report ID. For devices which only support a - single report, this must be set to 0x0. The remaining bytes - contain the report data. Since the Report ID is mandatory, - calls to hid_send_feature_report() will always contain one - more byte than the report contains. For example, if a hid - report is 16 bytes long, 17 bytes must be passed to - hid_send_feature_report(): the Report ID (or 0x0, for - devices which do not use numbered reports), followed by the - report data (16 bytes). In this example, the length passed - in would be 17. - - @ingroup API - @param device A device handle returned from hid_open(). - @param data The data to send, including the report number as - the first byte. - @param length The length in bytes of the data to send, including - the report number. - - @returns - This function returns the actual number of bytes written and - -1 on error. - */ - int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); - - /** @brief Get a feature report from a HID device. - - Set the first byte of @p data[] to the Report ID of the - report to be read. Make sure to allow space for this - extra byte in @p data[]. Upon return, the first byte will - still contain the Report ID, and the report data will - start in data[1]. - - @ingroup API - @param device A device handle returned from hid_open(). - @param data A buffer to put the read data into, including - the Report ID. Set the first byte of @p data[] to the - Report ID of the report to be read, or set it to zero - if your device does not use numbered reports. - @param length The number of bytes to read, including an - extra byte for the report ID. The buffer can be longer - than the actual report. - - @returns - This function returns the number of bytes read plus - one for the report ID (which is still in the first - byte), or -1 on error. - */ - int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); - - /** @brief Close a HID device. - - @ingroup API - @param device A device handle returned from hid_open(). - */ - void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); - - /** @brief Get The Manufacturer String from a HID device. - - @ingroup API - @param device A device handle returned from hid_open(). - @param string A wide string buffer to put the data into. - @param maxlen The length of the buffer in multiples of wchar_t. - - @returns - This function returns 0 on success and -1 on error. - */ - int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); - - /** @brief Get The Product String from a HID device. - - @ingroup API - @param device A device handle returned from hid_open(). - @param string A wide string buffer to put the data into. - @param maxlen The length of the buffer in multiples of wchar_t. - - @returns - This function returns 0 on success and -1 on error. - */ - int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); - - /** @brief Get The Serial Number String from a HID device. - - @ingroup API - @param device A device handle returned from hid_open(). - @param string A wide string buffer to put the data into. - @param maxlen The length of the buffer in multiples of wchar_t. - - @returns - This function returns 0 on success and -1 on error. - */ - int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); - - /** @brief Get a string from a HID device, based on its string index. - - @ingroup API - @param device A device handle returned from hid_open(). - @param string_index The index of the string to get. - @param string A wide string buffer to put the data into. - @param maxlen The length of the buffer in multiples of wchar_t. - - @returns - This function returns 0 on success and -1 on error. - */ - int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); - - /** @brief Get a string describing the last error which occurred. - - @ingroup API - @param device A device handle returned from hid_open(). - - @returns - This function returns a string containing the last error - which occurred or NULL if none has occurred. - */ - HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/include/log.h b/include/log.h deleted file mode 100644 index 2a64bef..0000000 --- a/include/log.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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 LOG_H -#define LOG_H - -#include -#include - -namespace nitrokey { - namespace log { - -//for MSVC -#ifdef ERROR -#undef ERROR -#endif - - - enum class Loglevel : int { - ERROR, - WARNING, - INFO, - DEBUG_L1, - DEBUG, - DEBUG_L2 - }; - - class LogHandler { - public: - virtual void print(const std::string &, Loglevel lvl) = 0; - protected: - std::string loglevel_to_str(Loglevel); - std::string format_message_to_string(const std::string &str, const Loglevel &lvl); - - }; - - class StdlogHandler : public LogHandler { - public: - virtual void print(const std::string &, Loglevel lvl); - }; - - class FunctionalLogHandler : public LogHandler { - using log_function_type = std::function; - log_function_type log_function; - public: - FunctionalLogHandler(log_function_type _log_function); - virtual void print(const std::string &, Loglevel lvl); - - }; - - extern StdlogHandler stdlog_handler; - - class Log { - public: - Log() : mp_loghandler(&stdlog_handler), m_loglevel(Loglevel::WARNING) {} - - static Log &instance() { - if (mp_instance == nullptr) mp_instance = new Log; - return *mp_instance; - } - - void operator()(const std::string &, Loglevel); - void set_loglevel(Loglevel lvl) { m_loglevel = lvl; } - void set_handler(LogHandler *handler) { mp_loghandler = handler; } - - private: - LogHandler *mp_loghandler; - Loglevel m_loglevel; - static std::string prefix; - public: - static void setPrefix(std::string prefix = std::string()); - - private: - - static Log *mp_instance; - }; - } -} - - -#ifdef NO_LOG -#define LOG(string, level) while(false){} -#define LOGD(string) while(false){} -#else -#define LOG(string, level) nitrokey::log::Log::instance()((string), (level)) -#define LOGD1(string) nitrokey::log::Log::instance()((string), (nitrokey::log::Loglevel::DEBUG_L1)) -#define LOGD(string) nitrokey::log::Log::instance()((string), (nitrokey::log::Loglevel::DEBUG_L2)) -#endif - -#endif diff --git a/include/misc.h b/include/misc.h deleted file mode 100644 index 88254dd..0000000 --- a/include/misc.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 MISC_H -#define MISC_H -#include -#include -#include -#include -#include "log.h" -#include "LibraryException.h" -#include -#include - - -namespace nitrokey { -namespace misc { - - template - std::string toHex(T value){ - using namespace std; - std::ostringstream oss; - oss << std::hex << std::setw(sizeof(value)*2) << std::setfill('0') << value; - return oss.str(); - } - - /** - * Copies string from pointer to fixed size C-style array. Src needs to be a valid C-string - eg. ended with '\0'. - * Throws when source is bigger than destination. - * @tparam T type of destination array - * @param dest fixed size destination array - * @param src pointer to source c-style valid string - */ - template - void strcpyT(T& dest, const char* src){ - - if (src == nullptr) -// throw EmptySourceStringException(slot_number); - return; - const size_t s_dest = sizeof dest; - LOG(std::string("strcpyT sizes dest src ") - +std::to_string(s_dest)+ " " - +std::to_string(strlen(src))+ " " - ,nitrokey::log::Loglevel::DEBUG_L2); - if (strlen(src) > s_dest){ - throw TooLongStringException(strlen(src), s_dest, src); - } - strncpy((char*) &dest, src, s_dest); - } - -#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) - template -typename T::CommandPayload get_payload(){ - //Create, initialize and return by value command payload - typename T::CommandPayload st; - bzero(&st, sizeof(st)); - return st; -} - - template - void execute_password_command(Tdev &stick, const char *password) { - auto p = get_payload(); - p.set_defaults(); - strcpyT(p.password, password); - CMDTYPE::CommandTransaction::run(stick, p); - } - - std::string hexdump(const uint8_t *p, size_t size, bool print_header=true, bool print_ascii=true, - bool print_empty=true); - uint32_t stm_crc32(const uint8_t *data, size_t size); - std::vector hex_string_to_byte(const char* hexString); -} -} - -#endif diff --git a/include/stick10_commands.h b/include/stick10_commands.h deleted file mode 100644 index 893b98f..0000000 --- a/include/stick10_commands.h +++ /dev/null @@ -1,884 +0,0 @@ -/* - * 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; - } __packed; - } __packed; - bool isValid() const { return enable_user_password!=delete_user_password; } - - 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; - }; - }; - 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 diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h deleted file mode 100644 index a04946f..0000000 --- a/include/stick10_commands_0.8.h +++ /dev/null @@ -1,344 +0,0 @@ -/* - * 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]; - - 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 diff --git a/include/stick20_commands.h b/include/stick20_commands.h deleted file mode 100644 index 4b75e6a..0000000 --- a/include/stick20_commands.h +++ /dev/null @@ -1,388 +0,0 @@ -/* - * 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 STICK20_COMMANDS_H -#define STICK20_COMMANDS_H - - - -#include -#include "command.h" -#include -#include -#include "device_proto.h" - -#pragma pack (push,1) - -namespace nitrokey { - namespace proto { - -/* -* STICK20 protocol command ids -* a superset (almost) of STICK10 -*/ - - namespace stick20 { - - class ChangeAdminUserPin20Current : - public PasswordCommand {}; - class ChangeAdminUserPin20New : - public PasswordCommand {}; - class UnlockUserPin : - public PasswordCommand {}; - - class EnableEncryptedPartition : public PasswordCommand {}; - class EnableHiddenEncryptedPartition : public PasswordCommand {}; - - class SetUnencryptedVolumeReadOnlyAdmin : - public PasswordCommand {}; - class SetUnencryptedVolumeReadWriteAdmin : - public PasswordCommand {}; - class SetEncryptedVolumeReadOnly : - public PasswordCommand {}; - class SetEncryptedVolumeReadWrite : - public PasswordCommand {}; - - //FIXME the volume disabling commands do not need password - class DisableEncryptedPartition : public PasswordCommand {}; - class DisableHiddenEncryptedPartition : public PasswordCommand {}; - - class EnableFirmwareUpdate : public PasswordCommand {}; - - class ChangeUpdatePassword : Command { - public: - struct CommandPayload { - uint8_t __gap; - uint8_t current_update_password[20]; - uint8_t __gap2; - uint8_t new_update_password[20]; - std::string dissect() const { - std::stringstream ss; - print_to_ss_volatile( current_update_password ); - print_to_ss_volatile( new_update_password ); - return ss.str(); - } - }; - - typedef Transaction - CommandTransaction; - }; - - class ExportFirmware : public PasswordCommand {}; - - class CreateNewKeys : - public PasswordCommand {}; - - - class FillSDCardWithRandomChars : Command { - public: - enum class ChosenVolumes : uint8_t { - all_volumes = 0, - encrypted_volume = 1 - }; - - struct CommandPayload { - uint8_t volume_flag; - uint8_t kind; - uint8_t admin_pin[20]; - - std::string dissect() const { - std::stringstream ss; - print_to_ss( (int) volume_flag ); - print_to_ss( kind ); - print_to_ss_volatile(admin_pin); - return ss.str(); - } - void set_kind_user() { - kind = (uint8_t) 'P'; - } - void set_defaults(){ - set_kind_user(); - volume_flag = static_cast(ChosenVolumes::encrypted_volume); - } - - } __packed; - - typedef Transaction::command_id(), - struct CommandPayload, struct EmptyPayload> - CommandTransaction; - }; - - namespace StorageCommandResponsePayload{ - using namespace DeviceResponseConstants; - static constexpr auto padding_size = - storage_data_absolute_address - header_size; - struct TransmissionData{ - uint8_t _padding[padding_size]; - - uint8_t SendCounter_u8; - uint8_t SendDataType_u8; - uint8_t FollowBytesFlag_u8; - uint8_t SendSize_u8; - - std::string dissect() const { - std::stringstream ss; - ss << "_padding:" << std::endl - << ::nitrokey::misc::hexdump((const uint8_t *) (_padding), - sizeof _padding); - print_to_ss((int) SendCounter_u8); - print_to_ss((int) SendDataType_u8); - print_to_ss((int) FollowBytesFlag_u8); - print_to_ss((int) SendSize_u8); - return ss.str(); - } - - } __packed; - } - - namespace DeviceConfigurationResponsePacket{ - - struct ResponsePayload { - StorageCommandResponsePayload::TransmissionData transmission_data; - - uint16_t MagicNumber_StickConfig_u16; - /** - * READ_WRITE_ACTIVE = ReadWriteFlagUncryptedVolume_u8 == 0; - */ - uint8_t ReadWriteFlagUncryptedVolume_u8; - uint8_t ReadWriteFlagCryptedVolume_u8; - - union{ - uint8_t VersionInfo_au8[4]; - struct { - uint8_t major; - uint8_t minor; - uint8_t _reserved2; - uint8_t build_iteration; - } __packed versionInfo; - } __packed; - - uint8_t ReadWriteFlagHiddenVolume_u8; - uint8_t FirmwareLocked_u8; - - union{ - uint8_t NewSDCardFound_u8; - struct { - bool NewCard :1; - uint8_t Counter :7; - } __packed NewSDCardFound_st; - } __packed; - - /** - * SD card FILLED with random chars - */ - uint8_t SDFillWithRandomChars_u8; - uint32_t ActiveSD_CardID_u32; - union{ - uint8_t VolumeActiceFlag_u8; - struct { - bool unencrypted :1; - bool encrypted :1; - bool hidden :1; - } __packed VolumeActiceFlag_st; - } __packed; - uint8_t NewSmartCardFound_u8; - uint8_t UserPwRetryCount; - uint8_t AdminPwRetryCount; - uint32_t ActiveSmartCardID_u32; - uint8_t StickKeysNotInitiated; - - bool isValid() const { return true; } - - std::string dissect() const { - std::stringstream ss; - - print_to_ss(transmission_data.dissect()); - print_to_ss( MagicNumber_StickConfig_u16 ); - print_to_ss((int) ReadWriteFlagUncryptedVolume_u8 ); - print_to_ss((int) ReadWriteFlagCryptedVolume_u8 ); - print_to_ss((int) ReadWriteFlagHiddenVolume_u8 ); - print_to_ss((int) versionInfo.major ); - print_to_ss((int) versionInfo.minor ); - print_to_ss((int) versionInfo.build_iteration ); - print_to_ss((int) FirmwareLocked_u8 ); - print_to_ss((int) NewSDCardFound_u8 ); - print_to_ss((int) NewSDCardFound_st.NewCard ); - print_to_ss((int) NewSDCardFound_st.Counter ); - print_to_ss((int) SDFillWithRandomChars_u8 ); - print_to_ss( ActiveSD_CardID_u32 ); - print_to_ss((int) VolumeActiceFlag_u8 ); - print_to_ss((int) VolumeActiceFlag_st.unencrypted ); - print_to_ss((int) VolumeActiceFlag_st.encrypted ); - print_to_ss((int) VolumeActiceFlag_st.hidden); - print_to_ss((int) NewSmartCardFound_u8 ); - print_to_ss((int) UserPwRetryCount ); - print_to_ss((int) AdminPwRetryCount ); - print_to_ss( ActiveSmartCardID_u32 ); - print_to_ss((int) StickKeysNotInitiated ); - - return ss.str(); - } - } __packed; - } - - class SendStartup : Command { - public: - struct CommandPayload { - uint64_t localtime; // POSIX seconds from epoch start, supports until year 2106 - std::string dissect() const { - std::stringstream ss; - print_to_ss( localtime ); - return ss.str(); - } - void set_defaults(){ - localtime = - std::chrono::duration_cast ( - std::chrono::system_clock::now().time_since_epoch()).count(); - } - }__packed; - - using ResponsePayload = DeviceConfigurationResponsePacket::ResponsePayload; - - typedef Transaction - CommandTransaction; - }; - - -// TODO fix original nomenclature - class SendSetReadonlyToUncryptedVolume : public PasswordCommand {}; - class SendSetReadwriteToUncryptedVolume : public PasswordCommand {}; - class SendClearNewSdCardFound : public PasswordCommand {}; - - class GetDeviceStatus : Command { - public: - using ResponsePayload = DeviceConfigurationResponsePacket::ResponsePayload; - - typedef Transaction - CommandTransaction; - }; - - class CheckSmartcardUsage : Command { - public: - typedef Transaction - CommandTransaction; - }; - - class GetSDCardOccupancy : Command { - public: - struct ResponsePayload { - uint8_t WriteLevelMin; - uint8_t WriteLevelMax; - uint8_t ReadLevelMin; - uint8_t ReadLevelMax; - std::string dissect() const { - std::stringstream ss; - print_to_ss((int) WriteLevelMin); - print_to_ss((int) WriteLevelMax); - print_to_ss((int) ReadLevelMin); - print_to_ss((int) ReadLevelMax); - return ss.str(); - } - } __packed; - - typedef Transaction - CommandTransaction; - }; - - - class SetupHiddenVolume : Command { - public: - constexpr static int MAX_HIDDEN_VOLUME_PASSWORD_SIZE = 20; - struct CommandPayload { - uint8_t SlotNr_u8; - uint8_t StartBlockPercent_u8; - uint8_t EndBlockPercent_u8; - uint8_t HiddenVolumePassword_au8[MAX_HIDDEN_VOLUME_PASSWORD_SIZE]; - std::string dissect() const { - std::stringstream ss; - print_to_ss((int) SlotNr_u8); - print_to_ss((int) StartBlockPercent_u8); - print_to_ss((int) EndBlockPercent_u8); - print_to_ss_volatile(HiddenVolumePassword_au8); - return ss.str(); - } - } __packed; - - typedef Transaction - CommandTransaction; - }; - - -//disable this command for now -// class LockFirmware : public PasswordCommand {}; - - class ProductionTest : Command { - public: - struct ResponsePayload { - - StorageCommandResponsePayload::TransmissionData transmission_data; - - uint8_t FirmwareVersion_au8[2]; // 2 byte // 2 - uint8_t FirmwareVersionInternal_u8; // 1 byte // 3 - uint8_t SD_Card_Size_u8; // 1 byte // 4 - uint32_t CPU_CardID_u32; // 4 byte // 8 - uint32_t SmartCardID_u32; // 4 byte // 12 - uint32_t SD_CardID_u32; // 4 byte // 16 - uint8_t SC_UserPwRetryCount; // User PIN retry count 1 byte // 17 - uint8_t SC_AdminPwRetryCount; // Admin PIN retry count 1 byte // 18 - uint8_t SD_Card_ManufacturingYear_u8; // 1 byte // 19 - uint8_t SD_Card_ManufacturingMonth_u8; // 1 byte // 20 - uint16_t SD_Card_OEM_u16; // 2 byte // 22 - uint16_t SD_WriteSpeed_u16; // in kbyte / sec 2 byte // 24 - uint8_t SD_Card_Manufacturer_u8; // 1 byte // 25 - - bool isValid() const { return true; } - - std::string dissect() const { - std::stringstream ss; - - print_to_ss(transmission_data.dissect()); - print_to_ss((int) FirmwareVersion_au8[0]); - print_to_ss((int) FirmwareVersion_au8[1]); - print_to_ss((int) FirmwareVersionInternal_u8); - print_to_ss((int) SD_Card_Size_u8); - print_to_ss( CPU_CardID_u32); - print_to_ss( SmartCardID_u32); - print_to_ss( SD_CardID_u32); - print_to_ss((int) SC_UserPwRetryCount); - print_to_ss((int) SC_AdminPwRetryCount); - print_to_ss((int) SD_Card_ManufacturingYear_u8); - print_to_ss((int) SD_Card_ManufacturingMonth_u8); - print_to_ss( SD_Card_OEM_u16); - print_to_ss( SD_WriteSpeed_u16); - print_to_ss((int) SD_Card_Manufacturer_u8); - return ss.str(); - } - - } __packed; - - typedef Transaction - CommandTransaction; - }; - - } - } -} - -#undef print_to_ss -#pragma pack (pop) - -#endif diff --git a/libnitrokey/CommandFailedException.h b/libnitrokey/CommandFailedException.h new file mode 100644 index 0000000..32bd6b7 --- /dev/null +++ b/libnitrokey/CommandFailedException.h @@ -0,0 +1,76 @@ +/* + * 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_COMMANDFAILEDEXCEPTION_H +#define LIBNITROKEY_COMMANDFAILEDEXCEPTION_H + +#include +#include +#include "log.h" +#include "command_id.h" + +using cs = nitrokey::proto::stick10::command_status; +using cs2 = nitrokey::proto::stick20::device_status; + +class CommandFailedException : public std::exception { +public: + const uint8_t last_command_id; + const uint8_t last_command_status; + + CommandFailedException(uint8_t last_command_id, uint8_t last_command_status) : + last_command_id(last_command_id), + last_command_status(last_command_status){ + LOG(std::string("CommandFailedException, status: ")+ std::to_string(last_command_status), nitrokey::log::Loglevel::DEBUG); + } + + virtual const char *what() const throw() { + return "Command execution has failed on device"; + } + + + bool reason_timestamp_warning() const throw(){ + return last_command_status == static_cast(cs::timestamp_warning); + } + + bool reason_AES_not_initialized() const throw(){ + return last_command_status == static_cast(cs::AES_dec_failed); + } + + bool reason_not_authorized() const throw(){ + return last_command_status == static_cast(cs::not_authorized); + } + + bool reason_slot_not_programmed() const throw(){ + return last_command_status == static_cast(cs::slot_not_programmed); + } + + bool reason_wrong_password() const throw(){ + return last_command_status == static_cast(cs::wrong_password); + } + + bool reason_smartcard_busy() const throw(){ + return last_command_status == static_cast(cs2::smartcard_error); + } + +}; + + +#endif //LIBNITROKEY_COMMANDFAILEDEXCEPTION_H diff --git a/libnitrokey/DeviceCommunicationExceptions.h b/libnitrokey/DeviceCommunicationExceptions.h new file mode 100644 index 0000000..f710d0b --- /dev/null +++ b/libnitrokey/DeviceCommunicationExceptions.h @@ -0,0 +1,73 @@ +/* + * 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_DEVICECOMMUNICATIONEXCEPTIONS_H +#define LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H + +#include +#include +#include +#include + + +class DeviceCommunicationException: public std::runtime_error +{ + std::string message; + static std::atomic_int occurred; +public: + DeviceCommunicationException(std::string _msg): std::runtime_error(_msg), message(_msg){ + ++occurred; + } + uint8_t getType() const {return 1;}; +// virtual const char* what() const throw() override { +// return message.c_str(); +// } + static bool has_occurred(){ return occurred > 0; }; + static void reset_occurred_flag(){ occurred = 0; }; +}; + +class DeviceNotConnected: public DeviceCommunicationException { +public: + DeviceNotConnected(std::string msg) : DeviceCommunicationException(msg){} + uint8_t getType() const {return 2;}; +}; + +class DeviceSendingFailure: public DeviceCommunicationException { +public: + DeviceSendingFailure(std::string msg) : DeviceCommunicationException(msg){} + uint8_t getType() const {return 3;}; +}; + +class DeviceReceivingFailure: public DeviceCommunicationException { +public: + DeviceReceivingFailure(std::string msg) : DeviceCommunicationException(msg){} + uint8_t getType() const {return 4;}; +}; + +class InvalidCRCReceived: public DeviceReceivingFailure { +public: + InvalidCRCReceived(std::string msg) : DeviceReceivingFailure(msg){} + uint8_t getType() const {return 5;}; +}; + + +#endif //LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H diff --git a/libnitrokey/LibraryException.h b/libnitrokey/LibraryException.h new file mode 100644 index 0000000..3b9d177 --- /dev/null +++ b/libnitrokey/LibraryException.h @@ -0,0 +1,118 @@ +/* + * 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_LIBRARYEXCEPTION_H +#define LIBNITROKEY_LIBRARYEXCEPTION_H + +#include +#include +#include +#include "log.h" + +class LibraryException: std::exception { +public: + virtual uint8_t exception_id()= 0; +}; + +class TargetBufferSmallerThanSource: public LibraryException { +public: + virtual uint8_t exception_id() override { + return 203; + } + +public: + size_t source_size; + size_t target_size; + + TargetBufferSmallerThanSource( + size_t source_size, size_t target_size + ) : source_size(source_size), target_size(target_size) {} + + virtual const char *what() const throw() override { + std::string s = " "; + auto ts = [](size_t x){ return std::to_string(x); }; + std::string msg = std::string("Target buffer size is smaller than source: [source size, buffer size]") + +s+ ts(source_size) +s+ ts(target_size); + return msg.c_str(); + } + +}; + +class InvalidHexString : public LibraryException { +public: + virtual uint8_t exception_id() override { + return 202; + } + +public: + uint8_t invalid_char; + + InvalidHexString (uint8_t invalid_char) : invalid_char( invalid_char) {} + + virtual const char *what() const throw() override { + return "Invalid character in hex string"; + } + +}; + +class InvalidSlotException : public LibraryException { +public: + virtual uint8_t exception_id() override { + return 201; + } + +public: + uint8_t slot_selected; + + InvalidSlotException(uint8_t slot_selected) : slot_selected(slot_selected) {} + + virtual const char *what() const throw() override { + return "Wrong slot selected"; + } + +}; + + + +class TooLongStringException : public LibraryException { +public: + virtual uint8_t exception_id() override { + return 200; + } + + std::size_t size_source; + std::size_t size_destination; + std::string message; + + TooLongStringException(size_t size_source, size_t size_destination, const std::string &message = "") : size_source( + size_source), size_destination(size_destination), message(message) { + LOG(std::string("TooLongStringException, size diff: ")+ std::to_string(size_source-size_destination), nitrokey::log::Loglevel::DEBUG); + + } + + virtual const char *what() const throw() override { + //TODO add sizes and message data to final message + return "Too long string has been supplied as an argument"; + } + +}; + +#endif //LIBNITROKEY_LIBRARYEXCEPTION_H diff --git a/libnitrokey/LongOperationInProgressException.h b/libnitrokey/LongOperationInProgressException.h new file mode 100644 index 0000000..865d6b5 --- /dev/null +++ b/libnitrokey/LongOperationInProgressException.h @@ -0,0 +1,45 @@ +/* + * 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_LONGOPERATIONINPROGRESSEXCEPTION_H +#define LIBNITROKEY_LONGOPERATIONINPROGRESSEXCEPTION_H + +#include "CommandFailedException.h" + +class LongOperationInProgressException : public CommandFailedException { + +public: + unsigned char progress_bar_value; + + LongOperationInProgressException( + unsigned char _command_id, uint8_t last_command_status, unsigned char _progress_bar_value) + : CommandFailedException(_command_id, last_command_status), progress_bar_value(_progress_bar_value){ + LOG( + std::string("LongOperationInProgressException, progress bar status: ")+ + std::to_string(progress_bar_value), nitrokey::log::Loglevel::DEBUG); + } + virtual const char *what() const throw() { + return "Device returned busy status with long operation in progress"; + } +}; + + +#endif //LIBNITROKEY_LONGOPERATIONINPROGRESSEXCEPTION_H diff --git a/libnitrokey/NitrokeyManager.h b/libnitrokey/NitrokeyManager.h new file mode 100644 index 0000000..ca58d24 --- /dev/null +++ b/libnitrokey/NitrokeyManager.h @@ -0,0 +1,283 @@ +/* + * 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_NITROKEYMANAGER_H +#define LIBNITROKEY_NITROKEYMANAGER_H + +#include "device.h" +#include "log.h" +#include "device_proto.h" +#include "stick10_commands.h" +#include "stick10_commands_0.8.h" +#include "stick20_commands.h" +#include +#include +#include + +namespace nitrokey { + using namespace nitrokey::device; + using namespace std; + using namespace nitrokey::proto::stick10; + using namespace nitrokey::proto::stick20; + using namespace nitrokey::proto; + using namespace nitrokey::log; + + +#ifdef __WIN32 +char * strndup(const char* str, size_t maxlen); +#endif + + class NitrokeyManager { + public: + static shared_ptr instance(); + + bool first_authenticate(const char *pin, const char *temporary_password); + bool write_HOTP_slot(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); + bool 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); + string get_HOTP_code(uint8_t slot_number, const char *user_temporary_password); + string get_TOTP_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, + uint8_t last_interval, + const char *user_temporary_password); + string get_TOTP_code(uint8_t slot_number, const char *user_temporary_password); + stick10::ReadSlot::ResponsePayload get_TOTP_slot_data(const uint8_t slot_number); + stick10::ReadSlot::ResponsePayload get_HOTP_slot_data(const uint8_t slot_number); + + bool set_time(uint64_t time); + bool get_time(uint64_t time = 0); + bool erase_totp_slot(uint8_t slot_number, const char *temporary_password); + bool erase_hotp_slot(uint8_t slot_number, const char *temporary_password); + std::vector list_devices(); + std::vector list_devices_by_cpuID(); + + /** + * Connect to the device using unique smartcard:datacard id. + * Needs list_device_by_cpuID() run first + * @param id Current ID of the target device + * @return true on success, false on failure + */ + bool connect_with_ID(const std::string id); + bool connect_with_path (std::string path); + bool connect(const char *device_model); + bool connect(); + bool disconnect(); + bool is_connected() throw() ; + bool could_current_device_be_enumerated(); + bool set_default_commands_delay(int delay); + + DeviceModel get_connected_device_model() const; + void set_debug(bool state); + stick10::GetStatus::ResponsePayload get_status(); + string get_status_as_string(); + string get_serial_number(); + + const char * get_totp_slot_name(uint8_t slot_number); + const char * get_hotp_slot_name(uint8_t slot_number); + + void change_user_PIN(const char *current_PIN, const char *new_PIN); + void change_admin_PIN(const char *current_PIN, const char *new_PIN); + + void enable_password_safe(const char *user_pin); + + vector get_password_safe_slot_status(); + + uint8_t get_admin_retry_count(); + uint8_t get_user_retry_count(); + + void lock_device(); + + const char *get_password_safe_slot_name(uint8_t slot_number); + const char *get_password_safe_slot_password(uint8_t slot_number); + const char *get_password_safe_slot_login(uint8_t slot_number); + + void + write_password_safe_slot(uint8_t slot_number, const char *slot_name, const char *slot_login, + const char *slot_password); + + void erase_password_safe_slot(uint8_t slot_number); + + void user_authenticate(const char *user_password, const char *temporary_password); + + void factory_reset(const char *admin_password); + + void build_aes_key(const char *admin_password); + + void unlock_user_password(const char *admin_password, const char *new_user_password); + + void write_config(uint8_t numlock, uint8_t capslock, uint8_t scrolllock, bool enable_user_password, + bool delete_user_password, const char *admin_temporary_password); + + vector read_config(); + + bool is_AES_supported(const char *user_password); + + void unlock_encrypted_volume(const char *user_password); + void lock_encrypted_volume(); + + void unlock_hidden_volume(const char *hidden_volume_password); + void lock_hidden_volume(); + + /** + * Sets unencrypted volume read-only. + * Works until v0.48 (incl. v0.50), where User PIN was sufficient + * Does nothing otherwise. + * @param user_pin User PIN + */ + void set_unencrypted_read_only(const char *user_pin); + + /** + * Sets unencrypted volume read-only. + * Works from v0.49 (except v0.50) accepts Admin PIN + * Does nothing otherwise. + * @param admin_pin Admin PIN + */ + void set_unencrypted_read_only_admin(const char *admin_pin); + + /** + * Sets unencrypted volume read-write. + * Works until v0.48 (incl. v0.50), where User PIN was sufficient + * Does nothing otherwise. + * @param user_pin User PIN + */ + void set_unencrypted_read_write(const char *user_pin); + + /** + * Sets unencrypted volume read-write. + * Works from v0.49 (except v0.50) accepts Admin PIN + * Does nothing otherwise. + * @param admin_pin Admin PIN + */ + void set_unencrypted_read_write_admin(const char *admin_pin); + + void export_firmware(const char *admin_pin); + void enable_firmware_update(const char *firmware_pin); + + void clear_new_sd_card_warning(const char *admin_pin); + + void fill_SD_card_with_random_data(const char *admin_pin); + + uint8_t get_SD_card_size(); + + void change_update_password(const char *current_update_password, const char *new_update_password); + + void create_hidden_volume(uint8_t slot_nr, uint8_t start_percent, uint8_t end_percent, + const char *hidden_volume_password); + + void send_startup(uint64_t seconds_from_epoch); + + const char * get_status_storage_as_string(); + stick20::DeviceConfigurationResponsePacket::ResponsePayload get_status_storage(); + + const char *get_SD_usage_data_as_string(); + std::pair get_SD_usage_data(); + + + int get_progress_bar_value(); + + ~NitrokeyManager(); + bool is_authorization_command_supported(); + bool is_320_OTP_secret_supported(); + + + template + void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device); + int get_minor_firmware_version(); + + explicit NitrokeyManager(); + void set_log_function(std::function log_function); + private: + + static shared_ptr _instance; + std::shared_ptr device; + std::string current_device_id; + public: + const string get_current_device_id() const; + + private: + std::unordered_map > connected_devices; + std::unordered_map > connected_devices_byID; + + + stick10::ReadSlot::ResponsePayload get_OTP_slot_data(const uint8_t slot_number); + bool is_valid_hotp_slot_number(uint8_t slot_number) const; + bool is_valid_totp_slot_number(uint8_t slot_number) const; + bool is_valid_password_safe_slot_number(uint8_t slot_number) const; + uint8_t get_internal_slot_number_for_hotp(uint8_t slot_number) const; + uint8_t get_internal_slot_number_for_totp(uint8_t slot_number) const; + bool erase_slot(uint8_t slot_number, const char *temporary_password); + const char * get_slot_name(uint8_t slot_number); + + template + void change_PIN_general(const char *current_PIN, const 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; + bool _disconnect_no_lock(); + + public: + bool set_current_device_speed(int retry_delay, int send_receive_delay); + void set_loglevel(Loglevel loglevel); + + void set_loglevel(int loglevel); + + /** + * Sets encrypted volume read-only. + * Supported from future versions of Storage. + * @param admin_pin Admin PIN + */ + void set_encrypted_volume_read_only(const char *admin_pin); + + /** + * Sets encrypted volume read-write. + * Supported from future versions of Storage. + * @param admin_pin Admin PIN + */ + void set_encrypted_volume_read_write(const char *admin_pin); + + int get_major_firmware_version(); + + bool is_smartcard_in_use(); + + /** + * Function to determine unencrypted volume PIN type + * @param minor_firmware_version + * @return Returns true, if set unencrypted volume ro/rw pin type is User, false otherwise. + */ + bool set_unencrypted_volume_rorw_pin_type_user(); + }; +} + + + +#endif //LIBNITROKEY_NITROKEYMANAGER_H diff --git a/libnitrokey/command.h b/libnitrokey/command.h new file mode 100644 index 0000000..6852bf0 --- /dev/null +++ b/libnitrokey/command.h @@ -0,0 +1,112 @@ +/* + * 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 COMMAND_H +#define COMMAND_H +#include +#include "command_id.h" +#include "cxx_semantics.h" + +#define print_to_ss(x) ( ss << " " << (#x) <<":\t" << (x) << std::endl ); +#ifdef LOG_VOLATILE_DATA +#define print_to_ss_volatile(x) print_to_ss(x); +#else +#define print_to_ss_volatile(x) ( ss << " " << (#x) <<":\t" << "***********" << std::endl ); +#endif +#define hexdump_to_ss(x) (ss << #x":\n"\ + << ::nitrokey::misc::hexdump((const uint8_t *) (&x), sizeof x, false)); + +namespace nitrokey { + namespace proto { + + template + class Command : semantics::non_constructible { + public: + constexpr static CommandID command_id() { return cmd_id; } + + template + std::string dissect(const T &) { + return std::string("Payload dissection is unavailable"); + } + }; + +namespace stick20{ + enum class PasswordKind : uint8_t { + User = 'P', + Admin = 'A', + AdminPrefixed + }; + + template + class PasswordCommand : public Command { + constexpr static CommandID _command_id() { return cmd_id; } + public: + struct CommandPayload { + uint8_t kind; + uint8_t password[password_length]; + + std::string dissect() const { + std::stringstream ss; + print_to_ss( kind ); + print_to_ss_volatile(password); + return ss.str(); + } + void set_kind_admin() { + kind = (uint8_t) 'A'; + } + void set_kind_admin_prefixed() { + kind = (uint8_t) 'P'; + } + void set_kind_user() { + kind = (uint8_t) 'P'; + } + + void set_defaults(){ + set_kind(Tpassword_kind); + } + + void set_kind(PasswordKind password_kind){ + switch (password_kind){ + case PasswordKind::Admin: + set_kind_admin(); + break; + case PasswordKind::User: + set_kind_user(); + break; + case PasswordKind::AdminPrefixed: + set_kind_admin_prefixed(); + break; + } + }; + + } __packed; + + //typedef Transaction::command_id(), struct CommandPayload, struct EmptyPayload> + // CommandTransaction; + using CommandTransaction = Transaction; + //using CommandTransaction = Transaction<_command_id(), CommandPayload, EmptyPayload>; + + }; + } + } +} + +#endif diff --git a/libnitrokey/command_id.h b/libnitrokey/command_id.h new file mode 100644 index 0000000..1092ea9 --- /dev/null +++ b/libnitrokey/command_id.h @@ -0,0 +1,152 @@ +/* + * 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 COMMAND_ID_H +#define COMMAND_ID_H +#include + +namespace nitrokey { +namespace proto { + namespace stick20 { + enum class device_status : uint8_t { + idle = 0, + ok, + busy, + wrong_password, + busy_progressbar, + password_matrix_ready, + no_user_password_unlock, // FIXME: translate on receive to command status error (fix in firmware?) + smartcard_error, + security_bit_active + }; + const int CMD_START_VALUE = 0x20; + const int CMD_END_VALUE = 0x60; + } + namespace stick10 { + enum class command_status : uint8_t { + ok = 0, + wrong_CRC, + wrong_slot, + slot_not_programmed, + wrong_password = 4, + not_authorized, + timestamp_warning, + no_name_error, + not_supported, + unknown_command, + AES_dec_failed + }; + enum class device_status : uint8_t { + ok = 0, + busy = 1, + error, + received_report, + }; + } + + +enum class CommandID : uint8_t { + GET_STATUS = 0x00, + WRITE_TO_SLOT = 0x01, + READ_SLOT_NAME = 0x02, + READ_SLOT = 0x03, + GET_CODE = 0x04, + WRITE_CONFIG = 0x05, + ERASE_SLOT = 0x06, + FIRST_AUTHENTICATE = 0x07, + AUTHORIZE = 0x08, + GET_PASSWORD_RETRY_COUNT = 0x09, + CLEAR_WARNING = 0x0A, + SET_TIME = 0x0B, + TEST_COUNTER = 0x0C, + TEST_TIME = 0x0D, + USER_AUTHENTICATE = 0x0E, + GET_USER_PASSWORD_RETRY_COUNT = 0x0F, + USER_AUTHORIZE = 0x10, + UNLOCK_USER_PASSWORD = 0x11, + LOCK_DEVICE = 0x12, + 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, + ENABLE_HIDDEN_CRYPTED_PARI = 0x20 + 2, + DISABLE_HIDDEN_CRYPTED_PARI = 0x20 + 3, + ENABLE_FIRMWARE_UPDATE = 0x20 + 4, //enables update mode + EXPORT_FIRMWARE_TO_FILE = 0x20 + 5, + GENERATE_NEW_KEYS = 0x20 + 6, + FILL_SD_CARD_WITH_RANDOM_CHARS = 0x20 + 7, + + WRITE_STATUS_DATA = 0x20 + 8, //@unused + ENABLE_READONLY_UNCRYPTED_LUN = 0x20 + 9, + ENABLE_READWRITE_UNCRYPTED_LUN = 0x20 + 10, + + SEND_PASSWORD_MATRIX = 0x20 + 11, //@unused + SEND_PASSWORD_MATRIX_PINDATA = 0x20 + 12, //@unused + SEND_PASSWORD_MATRIX_SETUP = 0x20 + 13, //@unused + + GET_DEVICE_STATUS = 0x20 + 14, + SEND_DEVICE_STATUS = 0x20 + 15, + + SEND_HIDDEN_VOLUME_PASSWORD = 0x20 + 16, //@unused + SEND_HIDDEN_VOLUME_SETUP = 0x20 + 17, + SEND_PASSWORD = 0x20 + 18, + SEND_NEW_PASSWORD = 0x20 + 19, + CLEAR_NEW_SD_CARD_FOUND = 0x20 + 20, + + SEND_STARTUP = 0x20 + 21, + SEND_CLEAR_STICK_KEYS_NOT_INITIATED = 0x20 + 22, + SEND_LOCK_STICK_HARDWARE = 0x20 + 23, //locks firmware upgrade + + PRODUCTION_TEST = 0x20 + 24, + SEND_DEBUG_DATA = 0x20 + 25, //@unused + + CHANGE_UPDATE_PIN = 0x20 + 26, + + //added in v0.48.5 + ENABLE_ADMIN_READONLY_UNCRYPTED_LUN = 0x20 + 28, + ENABLE_ADMIN_READWRITE_UNCRYPTED_LUN = 0x20 + 29, + ENABLE_ADMIN_READONLY_ENCRYPTED_LUN = 0x20 + 30, + ENABLE_ADMIN_READWRITE_ENCRYPTED_LUN = 0x20 + 31, + CHECK_SMARTCARD_USAGE = 0x20 + 32, + + GET_PW_SAFE_SLOT_STATUS = 0x60, + GET_PW_SAFE_SLOT_NAME = 0x61, + GET_PW_SAFE_SLOT_PASSWORD = 0x62, + GET_PW_SAFE_SLOT_LOGINNAME = 0x63, + SET_PW_SAFE_SLOT_DATA_1 = 0x64, + SET_PW_SAFE_SLOT_DATA_2 = 0x65, + PW_SAFE_ERASE_SLOT = 0x66, + PW_SAFE_ENABLE = 0x67, + PW_SAFE_INIT_KEY = 0x68, //@unused + PW_SAFE_SEND_DATA = 0x69, //@unused + SD_CARD_HIGH_WATERMARK = 0x70, + DETECT_SC_AES = 0x6a, + NEW_AES_KEY = 0x6b +}; + +const char *commandid_to_string(CommandID id); +} +} +#endif diff --git a/libnitrokey/cxx_semantics.h b/libnitrokey/cxx_semantics.h new file mode 100644 index 0000000..36ed142 --- /dev/null +++ b/libnitrokey/cxx_semantics.h @@ -0,0 +1,44 @@ +/* + * 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 CXX_SEMANTICS_H +#define CXX_SEMANTICS_H + +#ifndef _MSC_VER +#define __packed __attribute__((__packed__)) +#else +#define __packed +#endif + +#ifdef _MSC_VER +#define strdup _strdup +#endif + +/* + * There's no need to include Boost for a simple subset this project needs. + */ +namespace semantics { +class non_constructible { + non_constructible() {} +}; +} + +#endif diff --git a/libnitrokey/device.h b/libnitrokey/device.h new file mode 100644 index 0000000..f6d2380 --- /dev/null +++ b/libnitrokey/device.h @@ -0,0 +1,169 @@ +/* + * 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 DEVICE_H +#define DEVICE_H +#include +#include "hidapi/hidapi.h" +#include +#include +#include + +#define HID_REPORT_SIZE 65 + +#include + +namespace nitrokey { +namespace device { + using namespace std::chrono_literals; + using std::chrono::milliseconds; + + struct EnumClassHash + { + template + std::size_t operator()(T t) const + { + return static_cast(t); + } + }; + +enum class DeviceModel{ + PRO, + STORAGE +}; + +#include + +class Device { + +public: + + struct ErrorCounters{ + using cnt = std::atomic_int; + cnt wrong_CRC; + cnt CRC_other_than_awaited; + cnt busy; + cnt total_retries; + cnt sending_error; + cnt receiving_error; + cnt total_comm_runs; + cnt successful_storage_commands; + cnt command_successful_recv; + cnt recv_executed; + cnt sends_executed; + cnt busy_progressbar; + cnt command_result_not_equal_0_recv; + cnt communication_successful; + cnt low_level_reconnect; + std::string get_as_string(); + + } m_counters = {}; + + + Device(const uint16_t vid, const uint16_t pid, const DeviceModel model, + const milliseconds send_receive_delay, const int retry_receiving_count, + const milliseconds retry_timeout); + + virtual ~Device(); + + // lack of device is not actually an error, + // so it doesn't throw + virtual bool connect(); + virtual bool disconnect(); + + /* + * Sends packet of HID_REPORT_SIZE. + */ + virtual int send(const void *packet); + + /* + * Gets packet of HID_REPORT_SIZE. + * Can sleep. See below. + */ + virtual int recv(void *packet); + + /*** + * Returns true if some device is visible by OS with given VID and PID + * whether the device is connected through HID API or not. + * @return true if visible by OS + */ + bool could_be_enumerated(); + std::vector enumerate(); + + + void show_stats(); +// ErrorCounters get_stats(){ return m_counters; } + int get_retry_receiving_count() const { return m_retry_receiving_count; }; + int get_retry_sending_count() const { return m_retry_sending_count; }; + std::chrono::milliseconds get_retry_timeout() const { return m_retry_timeout; }; + std::chrono::milliseconds get_send_receive_delay() const {return m_send_receive_delay;} + + int get_last_command_status() {int a = std::atomic_exchange(&last_command_status, static_cast(0)); return a;}; + void set_last_command_status(uint8_t _err) { last_command_status = _err;} ; + bool last_command_sucessfull() const {return last_command_status == 0;}; + DeviceModel get_device_model() const {return m_model;} + void set_receiving_delay(std::chrono::milliseconds delay); + void set_retry_delay(std::chrono::milliseconds delay); + static void set_default_device_speed(int delay); + void setDefaultDelay(); + void set_path(const std::string path); + + + private: + std::atomic last_command_status; + void _reconnect(); + bool _connect(); + bool _disconnect(); + +protected: + const uint16_t m_vid; + const uint16_t m_pid; + const DeviceModel m_model; + + /* + * While the project uses Signal11 portable HIDAPI + * library, there's no way of doing it asynchronously, + * hence polling. + */ + const int m_retry_sending_count; + const int m_retry_receiving_count; + std::chrono::milliseconds m_retry_timeout; + std::chrono::milliseconds m_send_receive_delay; + std::atomicmp_devhandle; + std::string m_path; + + static std::atomic_int instances_count; + static std::chrono::milliseconds default_delay ; +}; + +class Stick10 : public Device { + public: + Stick10(); + +}; + +class Stick20 : public Device { + public: + Stick20(); +}; +} +} +#endif diff --git a/libnitrokey/device_proto.h b/libnitrokey/device_proto.h new file mode 100644 index 0000000..45a6c16 --- /dev/null +++ b/libnitrokey/device_proto.h @@ -0,0 +1,491 @@ +/* + * 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 DEVICE_PROTO_H +#define DEVICE_PROTO_H + +#include +#include +#include +#include +#include +// a local version for compatibility with Windows +#include +#include "cxx_semantics.h" +#include "device.h" +#include "misc.h" +#include "log.h" +#include "command_id.h" +#include "dissect.h" +#include "CommandFailedException.h" +#include "LongOperationInProgressException.h" + +#define STICK20_UPDATE_MODE_VID 0x03EB +#define STICK20_UPDATE_MODE_PID 0x2FF1 + +#define PAYLOAD_SIZE 53 +#define PWS_SLOT_COUNT 16 +#define PWS_SLOTNAME_LENGTH 11 +#define PWS_PASSWORD_LENGTH 20 +#define PWS_LOGINNAME_LENGTH 32 + +#define PWS_SEND_PASSWORD 0 +#define PWS_SEND_LOGINNAME 1 +#define PWS_SEND_TAB 2 +#define PWS_SEND_CR 3 + +#include +#include "DeviceCommunicationExceptions.h" +#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) + +namespace nitrokey { + namespace proto { + extern std::mutex send_receive_mtx; + + +/* + * POD types for HID proto commands + * Instances are meant to be __packed. + * + * TODO (future) support for Big Endian + */ +#pragma pack (push,1) +/* + * Every packet is a USB HID report (check USB spec) + */ + template + struct HIDReport { + uint8_t _zero; + CommandID command_id; // uint8_t + union { + uint8_t _padding[HID_REPORT_SIZE - 6]; + Payload payload; + } __packed; + uint32_t crc; + + // POD types can't have non-default constructors + // used in Transaction<>::run() + void initialize() { + bzero(this, sizeof *this); + command_id = cmd_id; + } + + uint32_t calculate_CRC() const { + // w/o leading zero, a part of each HID packet + // w/o 4-byte crc + return misc::stm_crc32((const uint8_t *) (this) + 1, + (size_t) (HID_REPORT_SIZE - 5)); + } + + void update_CRC() { crc = calculate_CRC(); } + + bool isCRCcorrect() const { return crc == calculate_CRC(); } + + bool isValid() const { + return true; + // return !_zero && payload.isValid() && isCRCcorrect(); + } + + operator std::string() const { + // Packet type is known upfront in normal operation. + // Can't be used to dissect random packets. + return QueryDissector::dissect(*this); + } + } __packed; + +/* + * Response payload (the parametrized type inside struct HIDReport) + * + * command_id member in incoming HIDReport structure carries the command + * type last used. + */ + namespace DeviceResponseConstants{ + //magic numbers from firmware + static constexpr auto storage_status_absolute_address = 21; + static constexpr auto storage_data_absolute_address = storage_status_absolute_address + 5; + static constexpr auto header_size = 8; //from _zero to last_command_status inclusive + static constexpr auto footer_size = 4; //crc + static constexpr auto wrapping_size = header_size + footer_size; + } + + template + struct DeviceResponse { + static constexpr auto storage_status_padding_size = + DeviceResponseConstants::storage_status_absolute_address - DeviceResponseConstants::header_size; + + uint8_t _zero; + uint8_t device_status; + uint8_t command_id; // originally last_command_type + uint32_t last_command_crc; + uint8_t last_command_status; + + union { + uint8_t _padding[HID_REPORT_SIZE - DeviceResponseConstants::wrapping_size]; + ResponsePayload payload; + struct { + uint8_t _storage_status_padding[storage_status_padding_size]; + uint8_t command_counter; + uint8_t command_id; + uint8_t device_status; //@see stick20::device_status + uint8_t progress_bar_value; + } __packed storage_status; + } __packed; + + uint32_t crc; + + void initialize() { bzero(this, sizeof *this); } + + uint32_t calculate_CRC() const { + // w/o leading zero, a part of each HID packet + // w/o 4-byte crc + return misc::stm_crc32((const uint8_t *) (this) + 1, + (size_t) (HID_REPORT_SIZE - 5)); + } + + void update_CRC() { crc = calculate_CRC(); } + bool isCRCcorrect() const { return crc == calculate_CRC(); } + bool isValid() const { + // return !_zero && payload.isValid() && isCRCcorrect() && + // command_id == (uint8_t)(cmd_id); + return crc != 0; + } + + operator std::string() const { + return ResponseDissector::dissect(*this); + } + } __packed; + + struct EmptyPayload { + bool isValid() const { return true; } + + std::string dissect() const { return std::string("Empty Payload."); } + } __packed; + + template + class ClearingProxy { + public: + ClearingProxy(command_packet &p) { + packet = p; + bzero(&p, sizeof(p)); + } + + ~ClearingProxy() { + bzero(&packet, sizeof(packet)); + } + + response_payload &data() { + return packet.payload; + } + + command_packet packet; + }; + + template + class Transaction : semantics::non_constructible { + public: + // Types declared in command class scope can't be reached from there. + typedef command_payload CommandPayload; + typedef response_payload ResponsePayload; + + + typedef struct HIDReport OutgoingPacket; + typedef struct DeviceResponse ResponsePacket; +#pragma pack (pop) + + static_assert(std::is_pod::value, + "outgoingpacket must be a pod type"); + static_assert(std::is_pod::value, + "ResponsePacket must be a POD type"); + static_assert(sizeof(OutgoingPacket) == HID_REPORT_SIZE, + "OutgoingPacket type is not the right size"); + static_assert(sizeof(ResponsePacket) == HID_REPORT_SIZE, + "ResponsePacket type is not the right size"); + + static uint32_t getCRC( + const command_payload &payload) { + OutgoingPacket outp; + outp.initialize(); + outp.payload = payload; + outp.update_CRC(); + return outp.crc; + } + + template + static void clear_packet(T &st) { + bzero(&st, sizeof(st)); + } + + static ClearingProxy run(std::shared_ptr dev, + const command_payload &payload) { + using namespace ::nitrokey::device; + using namespace ::nitrokey::log; + using namespace std::chrono_literals; + + std::lock_guard guard(send_receive_mtx); + + LOG(__FUNCTION__, Loglevel::DEBUG_L2); + + if (dev == nullptr){ + LOG(std::string("Throw: Device not initialized"), Loglevel::DEBUG_L1); + throw DeviceNotConnected("Device not initialized"); + } + dev->m_counters.total_comm_runs++; + + int status; + OutgoingPacket outp; + ResponsePacket resp; + + // POD types can't have non-default constructors + outp.initialize(); + resp.initialize(); + + outp.payload = payload; + outp.update_CRC(); + + LOG("-------------------", Loglevel::DEBUG); + LOG("Outgoing HID packet:", Loglevel::DEBUG); + LOG(static_cast(outp), Loglevel::DEBUG); + LOG(std::string("=> ") + std::string(commandid_to_string(static_cast(outp.command_id))), Loglevel::DEBUG_L1); + + + if (!outp.isValid()) { + LOG(std::string("Throw: Invalid outgoing packet"), Loglevel::DEBUG_L1); + throw DeviceSendingFailure("Invalid outgoing packet"); + } + + bool successful_communication = false; + int receiving_retry_counter = 0; + int sending_retry_counter = dev->get_retry_sending_count(); + while (sending_retry_counter-- > 0) { + dev->m_counters.sends_executed++; + status = dev->send(&outp); + if (status <= 0){ + //FIXME early disconnection not yet working properly +// LOG("Encountered communication error, disconnecting device", Loglevel::DEBUG_L2); +// dev->disconnect(); + dev->m_counters.sending_error++; + LOG(std::string("Throw: Device error while sending command "), Loglevel::DEBUG_L1); + throw DeviceSendingFailure( + std::string("Device error while sending command ") + + std::to_string(status)); + } + + std::this_thread::sleep_for(dev->get_send_receive_delay()); + + // FIXME make checks done in device:recv here + receiving_retry_counter = dev->get_retry_receiving_count(); + int busy_counter = 0; + auto retry_timeout = dev->get_retry_timeout(); + while (receiving_retry_counter-- > 0) { + dev->m_counters.recv_executed++; + status = dev->recv(&resp); + + if (dev->get_device_model() == DeviceModel::STORAGE && + resp.command_id >= stick20::CMD_START_VALUE && + resp.command_id < stick20::CMD_END_VALUE ) { + LOG(std::string("Detected storage device cmd, status: ") + + std::to_string(resp.storage_status.device_status), Loglevel::DEBUG_L2); + + resp.last_command_status = static_cast(stick10::command_status::ok); + switch (static_cast(resp.storage_status.device_status)) { + case stick20::device_status::idle : + case stick20::device_status::ok: + resp.device_status = static_cast(stick10::device_status::ok); + break; + case stick20::device_status::busy: + case stick20::device_status::busy_progressbar: //TODO this will be modified later for getting progressbar status + resp.device_status = static_cast(stick10::device_status::busy); + break; + case stick20::device_status::wrong_password: + resp.last_command_status = static_cast(stick10::command_status::wrong_password); + resp.device_status = static_cast(stick10::device_status::ok); + break; + case stick20::device_status::no_user_password_unlock: + resp.last_command_status = static_cast(stick10::command_status::AES_dec_failed); + resp.device_status = static_cast(stick10::device_status::ok); + break; + default: + LOG(std::string("Unknown storage device status, cannot translate: ") + + std::to_string(resp.storage_status.device_status), Loglevel::DEBUG); + resp.device_status = resp.storage_status.device_status; + break; + }; + } + + //Some of the commands return wrong CRC, for now skip checking it (TODO list and report) + //if (resp.device_status == 0 && resp.last_command_crc == outp.crc && resp.isCRCcorrect()) break; + auto CRC_equal_awaited = true; // resp.last_command_crc == outp.crc; + if (resp.device_status == static_cast(stick10::device_status::ok) && + CRC_equal_awaited && resp.isValid()){ + successful_communication = true; + break; + } + if (resp.device_status == static_cast(stick10::device_status::busy)) { + dev->m_counters.busy++; + + if (busy_counter++<10) { + receiving_retry_counter++; + LOG("Status busy, not decreasing receiving_retry_counter counter: " + + std::to_string(receiving_retry_counter), Loglevel::DEBUG_L2); + } else { + retry_timeout *= 2; + retry_timeout = std::min(retry_timeout, 300ms); + busy_counter = 0; + LOG("Status busy, decreasing receiving_retry_counter counter: " + + std::to_string(receiving_retry_counter) + ", current delay:" + + std::to_string(retry_timeout.count()), Loglevel::DEBUG); + LOG(std::string("Busy retry: status ") + + std::to_string(resp.storage_status.device_status) + + ", " + + std::to_string(retry_timeout.count()) + + "ms, counter " + + std::to_string(receiving_retry_counter) + + ", progress: " + + std::to_string(resp.storage_status.progress_bar_value) + , Loglevel::DEBUG_L1); + } + } + if (resp.device_status == static_cast(stick10::device_status::busy) && + static_cast(resp.storage_status.device_status) + == stick20::device_status::busy_progressbar){ + successful_communication = true; + break; + } + LOG(std::string("Retry status - dev status, awaited cmd crc, correct packet CRC: ") + + std::to_string(resp.device_status) + + " " + std::to_string(CRC_equal_awaited) + + " " + std::to_string(resp.isCRCcorrect()), Loglevel::DEBUG_L2); + + if (!resp.isCRCcorrect()) dev->m_counters.wrong_CRC++; + if (!CRC_equal_awaited) dev->m_counters.CRC_other_than_awaited++; + + + LOG( + "Device is not ready or received packet's last CRC is not equal to sent CRC packet, retrying...", + Loglevel::DEBUG_L2); + LOG("Invalid incoming HID packet:", Loglevel::DEBUG_L2); + LOG(static_cast(resp), Loglevel::DEBUG_L2); + dev->m_counters.total_retries++; + LOG(".", Loglevel::DEBUG_L1); + std::this_thread::sleep_for(retry_timeout); + continue; + } + if (successful_communication) break; + LOG(std::string("Resending (outer loop) "), Loglevel::DEBUG_L2); + LOG(std::string("sending_retry_counter count: ") + std::to_string(sending_retry_counter), + Loglevel::DEBUG); + } + + if(resp.last_command_crc != outp.crc){ + LOG(std::string("Accepting response with CRC other than expected ") + + "Command ID: " + std::to_string(resp.command_id) + " " + + commandid_to_string(static_cast(resp.command_id)) + " " + + "Reported by response and expected: " + std::to_string(resp.last_command_crc) + "!=" + std::to_string(outp.crc), + Loglevel::WARNING + ); + } + + dev->set_last_command_status(resp.last_command_status); // FIXME should be handled on device.recv + + clear_packet(outp); + + + if (status <= 0) { + dev->m_counters.receiving_error++; + LOG(std::string("Throw: Device error while executing command "), Loglevel::DEBUG_L1); + throw DeviceReceivingFailure( //FIXME replace with CriticalErrorException + std::string("Device error while executing command ") + + std::to_string(status)); + } + + LOG(std::string("<= ") + + std::string( + commandid_to_string(static_cast(resp.command_id)) + + std::string(" ") + + std::to_string(resp.device_status) + + std::string(" ") + + std::to_string(resp.storage_status.device_status) +// + std::to_string( status_translate_command(resp.storage_status.device_status)) + ), Loglevel::DEBUG_L1); + + LOG("Incoming HID packet:", Loglevel::DEBUG); + LOG(static_cast(resp), Loglevel::DEBUG); + if (dev->get_retry_receiving_count() - receiving_retry_counter > 2) { + LOG(std::string("Packet received with receiving_retry_counter count: ") + + std::to_string(receiving_retry_counter), + Loglevel::DEBUG_L1); + } + + if (resp.device_status == static_cast(stick10::device_status::busy) && + static_cast(resp.storage_status.device_status) + == stick20::device_status::busy_progressbar){ + dev->m_counters.busy_progressbar++; + LOG(std::string("Throw: Long operation in progress exception"), Loglevel::DEBUG_L1); + throw LongOperationInProgressException( + resp.command_id, resp.device_status, resp.storage_status.progress_bar_value); + } + + if (!resp.isValid()) { + LOG(std::string("Throw: Invalid incoming packet"), Loglevel::DEBUG_L1); + throw InvalidCRCReceived("Invalid incoming packet"); + } + if (receiving_retry_counter <= 0){ + LOG(std::string("Throw: \"Maximum receiving_retry_counter count reached for receiving response from the device!\"" + + std::to_string(receiving_retry_counter)), Loglevel::DEBUG_L1); + throw DeviceReceivingFailure( + "Maximum receiving_retry_counter count reached for receiving response from the device!"); + } + dev->m_counters.communication_successful++; + + if (resp.last_command_status != static_cast(stick10::command_status::ok)){ + dev->m_counters.command_result_not_equal_0_recv++; + LOG(std::string("Throw: CommandFailedException ") + std::to_string(resp.last_command_status), Loglevel::DEBUG_L1); + throw CommandFailedException(resp.command_id, resp.last_command_status); + } + + dev->m_counters.command_successful_recv++; + + if (dev->get_device_model() == DeviceModel::STORAGE && + resp.command_id >= stick20::CMD_START_VALUE && + resp.command_id < stick20::CMD_END_VALUE ) { + dev->m_counters.successful_storage_commands++; + } + + if (!resp.isCRCcorrect()) + LOG(std::string("Accepting response from device with invalid CRC. ") + + "Command ID: " + std::to_string(resp.command_id) + " " + + commandid_to_string(static_cast(resp.command_id)) + " " + + "Reported and calculated: " + std::to_string(resp.crc) + "!=" + std::to_string(resp.calculate_CRC()), + Loglevel::WARNING + ); + + // See: DeviceResponse + return resp; + } + + static ClearingProxy run(std::shared_ptr dev) { + command_payload empty_payload; + return run(dev, empty_payload); + } + }; + } +} +#endif diff --git a/libnitrokey/dissect.h b/libnitrokey/dissect.h new file mode 100644 index 0000000..690b5b7 --- /dev/null +++ b/libnitrokey/dissect.h @@ -0,0 +1,145 @@ +/* + * 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 + */ + +/* + * Protocol packet dissection + */ +#ifndef DISSECT_H +#define DISSECT_H +#include +#include +#include +#include "misc.h" +#include "cxx_semantics.h" +#include "command_id.h" +#include "device_proto.h" + +namespace nitrokey { +namespace proto { + +template +class QueryDissector : semantics::non_constructible { + public: + static std::string dissect(const HIDPacket &pod) { + std::stringstream out; + +#ifdef LOG_VOLATILE_DATA + out << "Raw HID packet:" << std::endl; + out << ::nitrokey::misc::hexdump((const uint8_t *)(&pod), sizeof pod); +#endif + + out << "Contents:" << std::endl; + out << "Command ID:\t" << commandid_to_string((CommandID)(pod.command_id)) + << std::endl; + out << "CRC:\t" + << std::hex << std::setw(2) << std::setfill('0') + << pod.crc << std::endl; + + out << "Payload:" << std::endl; + out << pod.payload.dissect(); + return out.str(); + } +}; + + + + +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) + +#ifdef LOG_VOLATILE_DATA + out << "Raw HID packet:" << std::endl; + out << ::nitrokey::misc::hexdump((const uint8_t *)(&pod), sizeof pod); +#endif + + out << "Device status:\t" << pod.device_status + 0 << " " + << 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 << " " + << status_translate_command(pod.last_command_status) << std::endl; + out << "CRC:\t" + << std::hex << std::setw(2) << std::setfill('0') + << pod.crc << std::endl; + if((int)pod.command_id == pod.storage_status.command_id){ + out << "Storage stick status (where applicable):" << std::endl; +#define d(x) out << " "#x": \t"<< std::hex << std::setw(2) \ + << std::setfill('0')<< static_cast(x) << std::endl; + d(pod.storage_status.command_counter); + d(pod.storage_status.command_id); + d(pod.storage_status.device_status); + d(pod.storage_status.progress_bar_value); +#undef d + } + + out << "Payload:" << std::endl; + out << pod.payload.dissect(); + return out.str(); + } +}; +} +} + +#endif diff --git a/libnitrokey/hidapi/hidapi.h b/libnitrokey/hidapi/hidapi.h new file mode 100644 index 0000000..e5bc2dc --- /dev/null +++ b/libnitrokey/hidapi/hidapi.h @@ -0,0 +1,391 @@ +/******************************************************* + HIDAPI - Multi-Platform library for + communication with HID devices. + + Alan Ott + Signal 11 Software + + 8/22/2009 + + Copyright 2009, All Rights Reserved. + + At the discretion of the user of this library, + this software may be licensed under the terms of the + GNU General Public License v3, a BSD-Style license, or the + original HIDAPI license as outlined in the LICENSE.txt, + LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt + files located at the root of the source distribution. + These files may also be found in the public source + code repository located at: + http://github.com/signal11/hidapi . +********************************************************/ + +/** @file + * @defgroup API hidapi API + */ + +#ifndef HIDAPI_H__ +#define HIDAPI_H__ + +#include + +#ifdef _WIN32 + #define HID_API_EXPORT __declspec(dllexport) + #define HID_API_CALL +#else + #define HID_API_EXPORT /**< API export macro */ + #define HID_API_CALL /**< API call macro */ +#endif + +#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ + +#ifdef __cplusplus +extern "C" { +#endif + struct hid_device_; + typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ + + /** hidapi info structure */ + struct hid_device_info { + /** Platform-specific device path */ + char *path; + /** Device Vendor ID */ + unsigned short vendor_id; + /** Device Product ID */ + unsigned short product_id; + /** Serial Number */ + wchar_t *serial_number; + /** Device Release Number in binary-coded decimal, + also known as Device Version Number */ + unsigned short release_number; + /** Manufacturer String */ + wchar_t *manufacturer_string; + /** Product string */ + wchar_t *product_string; + /** Usage Page for this Device/Interface + (Windows/Mac only). */ + unsigned short usage_page; + /** Usage for this Device/Interface + (Windows/Mac only).*/ + unsigned short usage; + /** The USB interface which this logical device + represents. Valid on both Linux implementations + in all cases, and valid on the Windows implementation + only if the device contains more than one interface. */ + int interface_number; + + /** Pointer to the next device */ + struct hid_device_info *next; + }; + + + /** @brief Initialize the HIDAPI library. + + This function initializes the HIDAPI library. Calling it is not + strictly necessary, as it will be called automatically by + hid_enumerate() and any of the hid_open_*() functions if it is + needed. This function should be called at the beginning of + execution however, if there is a chance of HIDAPI handles + being opened by different threads simultaneously. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_init(void); + + /** @brief Finalize the HIDAPI library. + + This function frees all of the static data associated with + HIDAPI. It should be called at the end of execution to avoid + memory leaks. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_exit(void); + + /** @brief Enumerate the HID Devices. + + This function returns a linked list of all the HID devices + attached to the system which match vendor_id and product_id. + If @p vendor_id is set to 0 then any vendor matches. + If @p product_id is set to 0 then any product matches. + If @p vendor_id and @p product_id are both set to 0, then + all HID devices will be returned. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the types of device + to open. + @param product_id The Product ID (PID) of the types of + device to open. + + @returns + This function returns a pointer to a linked list of type + struct #hid_device, containing information about the HID devices + attached to the system, or NULL in the case of failure. Free + this linked list by calling hid_free_enumeration(). + */ + struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); + + /** @brief Free an enumeration Linked List + + This function frees a linked list created by hid_enumerate(). + + @ingroup API + @param devs Pointer to a list of struct_device returned from + hid_enumerate(). + */ + void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); + + /** @brief Open a HID device using a Vendor ID (VID), Product ID + (PID) and optionally a serial number. + + If @p serial_number is NULL, the first device with the + specified VID and PID is opened. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the device to open. + @param product_id The Product ID (PID) of the device to open. + @param serial_number The Serial Number of the device to open + (Optionally NULL). + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); + + /** @brief Open a HID device by its path name. + + The path name be determined by calling hid_enumerate(), or a + platform-specific path name can be used (eg: /dev/hidraw0 on + Linux). + + @ingroup API + @param path The path name of the device to open + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); + + /** @brief Write an Output report to a HID device. + + The first byte of @p data[] must contain the Report ID. For + devices which only support a single report, this must be set + to 0x0. The remaining bytes contain the report data. Since + the Report ID is mandatory, calls to hid_write() will always + contain one more byte than the report contains. For example, + if a hid report is 16 bytes long, 17 bytes must be passed to + hid_write(), the Report ID (or 0x0, for devices with a + single report), followed by the report data (16 bytes). In + this example, the length passed in would be 17. + + hid_write() will send the data on the first OUT endpoint, if + one exists. If it does not, it will send the data through + the Control Endpoint (Endpoint 0). + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Read an Input report from a HID device with timeout. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + @param milliseconds timeout in milliseconds or -1 for blocking wait. + + @returns + This function returns the actual number of bytes read and + -1 on error. If no packet was available to be read within + the timeout period, this function returns 0. + */ + int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); + + /** @brief Read an Input report from a HID device. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + + @returns + This function returns the actual number of bytes read and + -1 on error. If no packet was available to be read and + the handle is in non-blocking mode, this function returns 0. + */ + int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); + + /** @brief Set the device handle to be non-blocking. + + In non-blocking mode calls to hid_read() will return + immediately with a value of 0 if there is no data to be + read. In blocking mode, hid_read() will wait (block) until + there is data to read before returning. + + Nonblocking can be turned on and off at any time. + + @ingroup API + @param device A device handle returned from hid_open(). + @param nonblock enable or not the nonblocking reads + - 1 to enable nonblocking + - 0 to disable nonblocking. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); + + /** @brief Send a Feature report to the device. + + Feature reports are sent over the Control endpoint as a + Set_Report transfer. The first byte of @p data[] must + contain the Report ID. For devices which only support a + single report, this must be set to 0x0. The remaining bytes + contain the report data. Since the Report ID is mandatory, + calls to hid_send_feature_report() will always contain one + more byte than the report contains. For example, if a hid + report is 16 bytes long, 17 bytes must be passed to + hid_send_feature_report(): the Report ID (or 0x0, for + devices which do not use numbered reports), followed by the + report data (16 bytes). In this example, the length passed + in would be 17. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send, including + the report number. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Get a feature report from a HID device. + + Set the first byte of @p data[] to the Report ID of the + report to be read. Make sure to allow space for this + extra byte in @p data[]. Upon return, the first byte will + still contain the Report ID, and the report data will + start in data[1]. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into, including + the Report ID. Set the first byte of @p data[] to the + Report ID of the report to be read, or set it to zero + if your device does not use numbered reports. + @param length The number of bytes to read, including an + extra byte for the report ID. The buffer can be longer + than the actual report. + + @returns + This function returns the number of bytes read plus + one for the report ID (which is still in the first + byte), or -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); + + /** @brief Close a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + */ + void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); + + /** @brief Get The Manufacturer String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Product String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Serial Number String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get a string from a HID device, based on its string index. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string_index The index of the string to get. + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); + + /** @brief Get a string describing the last error which occurred. + + @ingroup API + @param device A device handle returned from hid_open(). + + @returns + This function returns a string containing the last error + which occurred or NULL if none has occurred. + */ + HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libnitrokey/log.h b/libnitrokey/log.h new file mode 100644 index 0000000..2a64bef --- /dev/null +++ b/libnitrokey/log.h @@ -0,0 +1,108 @@ +/* + * 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 LOG_H +#define LOG_H + +#include +#include + +namespace nitrokey { + namespace log { + +//for MSVC +#ifdef ERROR +#undef ERROR +#endif + + + enum class Loglevel : int { + ERROR, + WARNING, + INFO, + DEBUG_L1, + DEBUG, + DEBUG_L2 + }; + + class LogHandler { + public: + virtual void print(const std::string &, Loglevel lvl) = 0; + protected: + std::string loglevel_to_str(Loglevel); + std::string format_message_to_string(const std::string &str, const Loglevel &lvl); + + }; + + class StdlogHandler : public LogHandler { + public: + virtual void print(const std::string &, Loglevel lvl); + }; + + class FunctionalLogHandler : public LogHandler { + using log_function_type = std::function; + log_function_type log_function; + public: + FunctionalLogHandler(log_function_type _log_function); + virtual void print(const std::string &, Loglevel lvl); + + }; + + extern StdlogHandler stdlog_handler; + + class Log { + public: + Log() : mp_loghandler(&stdlog_handler), m_loglevel(Loglevel::WARNING) {} + + static Log &instance() { + if (mp_instance == nullptr) mp_instance = new Log; + return *mp_instance; + } + + void operator()(const std::string &, Loglevel); + void set_loglevel(Loglevel lvl) { m_loglevel = lvl; } + void set_handler(LogHandler *handler) { mp_loghandler = handler; } + + private: + LogHandler *mp_loghandler; + Loglevel m_loglevel; + static std::string prefix; + public: + static void setPrefix(std::string prefix = std::string()); + + private: + + static Log *mp_instance; + }; + } +} + + +#ifdef NO_LOG +#define LOG(string, level) while(false){} +#define LOGD(string) while(false){} +#else +#define LOG(string, level) nitrokey::log::Log::instance()((string), (level)) +#define LOGD1(string) nitrokey::log::Log::instance()((string), (nitrokey::log::Loglevel::DEBUG_L1)) +#define LOGD(string) nitrokey::log::Log::instance()((string), (nitrokey::log::Loglevel::DEBUG_L2)) +#endif + +#endif diff --git a/libnitrokey/misc.h b/libnitrokey/misc.h new file mode 100644 index 0000000..88254dd --- /dev/null +++ b/libnitrokey/misc.h @@ -0,0 +1,94 @@ +/* + * 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 MISC_H +#define MISC_H +#include +#include +#include +#include +#include "log.h" +#include "LibraryException.h" +#include +#include + + +namespace nitrokey { +namespace misc { + + template + std::string toHex(T value){ + using namespace std; + std::ostringstream oss; + oss << std::hex << std::setw(sizeof(value)*2) << std::setfill('0') << value; + return oss.str(); + } + + /** + * Copies string from pointer to fixed size C-style array. Src needs to be a valid C-string - eg. ended with '\0'. + * Throws when source is bigger than destination. + * @tparam T type of destination array + * @param dest fixed size destination array + * @param src pointer to source c-style valid string + */ + template + void strcpyT(T& dest, const char* src){ + + if (src == nullptr) +// throw EmptySourceStringException(slot_number); + return; + const size_t s_dest = sizeof dest; + LOG(std::string("strcpyT sizes dest src ") + +std::to_string(s_dest)+ " " + +std::to_string(strlen(src))+ " " + ,nitrokey::log::Loglevel::DEBUG_L2); + if (strlen(src) > s_dest){ + throw TooLongStringException(strlen(src), s_dest, src); + } + strncpy((char*) &dest, src, s_dest); + } + +#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) + template +typename T::CommandPayload get_payload(){ + //Create, initialize and return by value command payload + typename T::CommandPayload st; + bzero(&st, sizeof(st)); + return st; +} + + template + void execute_password_command(Tdev &stick, const char *password) { + auto p = get_payload(); + p.set_defaults(); + strcpyT(p.password, password); + CMDTYPE::CommandTransaction::run(stick, p); + } + + std::string hexdump(const uint8_t *p, size_t size, bool print_header=true, bool print_ascii=true, + bool print_empty=true); + uint32_t stm_crc32(const uint8_t *data, size_t size); + std::vector hex_string_to_byte(const char* hexString); +} +} + +#endif diff --git a/libnitrokey/stick10_commands.h b/libnitrokey/stick10_commands.h new file mode 100644 index 0000000..893b98f --- /dev/null +++ b/libnitrokey/stick10_commands.h @@ -0,0 +1,884 @@ +/* + * 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; + } __packed; + } __packed; + bool isValid() const { return enable_user_password!=delete_user_password; } + + 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; + }; + }; + 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 diff --git a/libnitrokey/stick10_commands_0.8.h b/libnitrokey/stick10_commands_0.8.h new file mode 100644 index 0000000..a04946f --- /dev/null +++ b/libnitrokey/stick10_commands_0.8.h @@ -0,0 +1,344 @@ +/* + * 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]; + + 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 diff --git a/libnitrokey/stick20_commands.h b/libnitrokey/stick20_commands.h new file mode 100644 index 0000000..4b75e6a --- /dev/null +++ b/libnitrokey/stick20_commands.h @@ -0,0 +1,388 @@ +/* + * 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 STICK20_COMMANDS_H +#define STICK20_COMMANDS_H + + + +#include +#include "command.h" +#include +#include +#include "device_proto.h" + +#pragma pack (push,1) + +namespace nitrokey { + namespace proto { + +/* +* STICK20 protocol command ids +* a superset (almost) of STICK10 +*/ + + namespace stick20 { + + class ChangeAdminUserPin20Current : + public PasswordCommand {}; + class ChangeAdminUserPin20New : + public PasswordCommand {}; + class UnlockUserPin : + public PasswordCommand {}; + + class EnableEncryptedPartition : public PasswordCommand {}; + class EnableHiddenEncryptedPartition : public PasswordCommand {}; + + class SetUnencryptedVolumeReadOnlyAdmin : + public PasswordCommand {}; + class SetUnencryptedVolumeReadWriteAdmin : + public PasswordCommand {}; + class SetEncryptedVolumeReadOnly : + public PasswordCommand {}; + class SetEncryptedVolumeReadWrite : + public PasswordCommand {}; + + //FIXME the volume disabling commands do not need password + class DisableEncryptedPartition : public PasswordCommand {}; + class DisableHiddenEncryptedPartition : public PasswordCommand {}; + + class EnableFirmwareUpdate : public PasswordCommand {}; + + class ChangeUpdatePassword : Command { + public: + struct CommandPayload { + uint8_t __gap; + uint8_t current_update_password[20]; + uint8_t __gap2; + uint8_t new_update_password[20]; + std::string dissect() const { + std::stringstream ss; + print_to_ss_volatile( current_update_password ); + print_to_ss_volatile( new_update_password ); + return ss.str(); + } + }; + + typedef Transaction + CommandTransaction; + }; + + class ExportFirmware : public PasswordCommand {}; + + class CreateNewKeys : + public PasswordCommand {}; + + + class FillSDCardWithRandomChars : Command { + public: + enum class ChosenVolumes : uint8_t { + all_volumes = 0, + encrypted_volume = 1 + }; + + struct CommandPayload { + uint8_t volume_flag; + uint8_t kind; + uint8_t admin_pin[20]; + + std::string dissect() const { + std::stringstream ss; + print_to_ss( (int) volume_flag ); + print_to_ss( kind ); + print_to_ss_volatile(admin_pin); + return ss.str(); + } + void set_kind_user() { + kind = (uint8_t) 'P'; + } + void set_defaults(){ + set_kind_user(); + volume_flag = static_cast(ChosenVolumes::encrypted_volume); + } + + } __packed; + + typedef Transaction::command_id(), + struct CommandPayload, struct EmptyPayload> + CommandTransaction; + }; + + namespace StorageCommandResponsePayload{ + using namespace DeviceResponseConstants; + static constexpr auto padding_size = + storage_data_absolute_address - header_size; + struct TransmissionData{ + uint8_t _padding[padding_size]; + + uint8_t SendCounter_u8; + uint8_t SendDataType_u8; + uint8_t FollowBytesFlag_u8; + uint8_t SendSize_u8; + + std::string dissect() const { + std::stringstream ss; + ss << "_padding:" << std::endl + << ::nitrokey::misc::hexdump((const uint8_t *) (_padding), + sizeof _padding); + print_to_ss((int) SendCounter_u8); + print_to_ss((int) SendDataType_u8); + print_to_ss((int) FollowBytesFlag_u8); + print_to_ss((int) SendSize_u8); + return ss.str(); + } + + } __packed; + } + + namespace DeviceConfigurationResponsePacket{ + + struct ResponsePayload { + StorageCommandResponsePayload::TransmissionData transmission_data; + + uint16_t MagicNumber_StickConfig_u16; + /** + * READ_WRITE_ACTIVE = ReadWriteFlagUncryptedVolume_u8 == 0; + */ + uint8_t ReadWriteFlagUncryptedVolume_u8; + uint8_t ReadWriteFlagCryptedVolume_u8; + + union{ + uint8_t VersionInfo_au8[4]; + struct { + uint8_t major; + uint8_t minor; + uint8_t _reserved2; + uint8_t build_iteration; + } __packed versionInfo; + } __packed; + + uint8_t ReadWriteFlagHiddenVolume_u8; + uint8_t FirmwareLocked_u8; + + union{ + uint8_t NewSDCardFound_u8; + struct { + bool NewCard :1; + uint8_t Counter :7; + } __packed NewSDCardFound_st; + } __packed; + + /** + * SD card FILLED with random chars + */ + uint8_t SDFillWithRandomChars_u8; + uint32_t ActiveSD_CardID_u32; + union{ + uint8_t VolumeActiceFlag_u8; + struct { + bool unencrypted :1; + bool encrypted :1; + bool hidden :1; + } __packed VolumeActiceFlag_st; + } __packed; + uint8_t NewSmartCardFound_u8; + uint8_t UserPwRetryCount; + uint8_t AdminPwRetryCount; + uint32_t ActiveSmartCardID_u32; + uint8_t StickKeysNotInitiated; + + bool isValid() const { return true; } + + std::string dissect() const { + std::stringstream ss; + + print_to_ss(transmission_data.dissect()); + print_to_ss( MagicNumber_StickConfig_u16 ); + print_to_ss((int) ReadWriteFlagUncryptedVolume_u8 ); + print_to_ss((int) ReadWriteFlagCryptedVolume_u8 ); + print_to_ss((int) ReadWriteFlagHiddenVolume_u8 ); + print_to_ss((int) versionInfo.major ); + print_to_ss((int) versionInfo.minor ); + print_to_ss((int) versionInfo.build_iteration ); + print_to_ss((int) FirmwareLocked_u8 ); + print_to_ss((int) NewSDCardFound_u8 ); + print_to_ss((int) NewSDCardFound_st.NewCard ); + print_to_ss((int) NewSDCardFound_st.Counter ); + print_to_ss((int) SDFillWithRandomChars_u8 ); + print_to_ss( ActiveSD_CardID_u32 ); + print_to_ss((int) VolumeActiceFlag_u8 ); + print_to_ss((int) VolumeActiceFlag_st.unencrypted ); + print_to_ss((int) VolumeActiceFlag_st.encrypted ); + print_to_ss((int) VolumeActiceFlag_st.hidden); + print_to_ss((int) NewSmartCardFound_u8 ); + print_to_ss((int) UserPwRetryCount ); + print_to_ss((int) AdminPwRetryCount ); + print_to_ss( ActiveSmartCardID_u32 ); + print_to_ss((int) StickKeysNotInitiated ); + + return ss.str(); + } + } __packed; + } + + class SendStartup : Command { + public: + struct CommandPayload { + uint64_t localtime; // POSIX seconds from epoch start, supports until year 2106 + std::string dissect() const { + std::stringstream ss; + print_to_ss( localtime ); + return ss.str(); + } + void set_defaults(){ + localtime = + std::chrono::duration_cast ( + std::chrono::system_clock::now().time_since_epoch()).count(); + } + }__packed; + + using ResponsePayload = DeviceConfigurationResponsePacket::ResponsePayload; + + typedef Transaction + CommandTransaction; + }; + + +// TODO fix original nomenclature + class SendSetReadonlyToUncryptedVolume : public PasswordCommand {}; + class SendSetReadwriteToUncryptedVolume : public PasswordCommand {}; + class SendClearNewSdCardFound : public PasswordCommand {}; + + class GetDeviceStatus : Command { + public: + using ResponsePayload = DeviceConfigurationResponsePacket::ResponsePayload; + + typedef Transaction + CommandTransaction; + }; + + class CheckSmartcardUsage : Command { + public: + typedef Transaction + CommandTransaction; + }; + + class GetSDCardOccupancy : Command { + public: + struct ResponsePayload { + uint8_t WriteLevelMin; + uint8_t WriteLevelMax; + uint8_t ReadLevelMin; + uint8_t ReadLevelMax; + std::string dissect() const { + std::stringstream ss; + print_to_ss((int) WriteLevelMin); + print_to_ss((int) WriteLevelMax); + print_to_ss((int) ReadLevelMin); + print_to_ss((int) ReadLevelMax); + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + }; + + + class SetupHiddenVolume : Command { + public: + constexpr static int MAX_HIDDEN_VOLUME_PASSWORD_SIZE = 20; + struct CommandPayload { + uint8_t SlotNr_u8; + uint8_t StartBlockPercent_u8; + uint8_t EndBlockPercent_u8; + uint8_t HiddenVolumePassword_au8[MAX_HIDDEN_VOLUME_PASSWORD_SIZE]; + std::string dissect() const { + std::stringstream ss; + print_to_ss((int) SlotNr_u8); + print_to_ss((int) StartBlockPercent_u8); + print_to_ss((int) EndBlockPercent_u8); + print_to_ss_volatile(HiddenVolumePassword_au8); + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + }; + + +//disable this command for now +// class LockFirmware : public PasswordCommand {}; + + class ProductionTest : Command { + public: + struct ResponsePayload { + + StorageCommandResponsePayload::TransmissionData transmission_data; + + uint8_t FirmwareVersion_au8[2]; // 2 byte // 2 + uint8_t FirmwareVersionInternal_u8; // 1 byte // 3 + uint8_t SD_Card_Size_u8; // 1 byte // 4 + uint32_t CPU_CardID_u32; // 4 byte // 8 + uint32_t SmartCardID_u32; // 4 byte // 12 + uint32_t SD_CardID_u32; // 4 byte // 16 + uint8_t SC_UserPwRetryCount; // User PIN retry count 1 byte // 17 + uint8_t SC_AdminPwRetryCount; // Admin PIN retry count 1 byte // 18 + uint8_t SD_Card_ManufacturingYear_u8; // 1 byte // 19 + uint8_t SD_Card_ManufacturingMonth_u8; // 1 byte // 20 + uint16_t SD_Card_OEM_u16; // 2 byte // 22 + uint16_t SD_WriteSpeed_u16; // in kbyte / sec 2 byte // 24 + uint8_t SD_Card_Manufacturer_u8; // 1 byte // 25 + + bool isValid() const { return true; } + + std::string dissect() const { + std::stringstream ss; + + print_to_ss(transmission_data.dissect()); + print_to_ss((int) FirmwareVersion_au8[0]); + print_to_ss((int) FirmwareVersion_au8[1]); + print_to_ss((int) FirmwareVersionInternal_u8); + print_to_ss((int) SD_Card_Size_u8); + print_to_ss( CPU_CardID_u32); + print_to_ss( SmartCardID_u32); + print_to_ss( SD_CardID_u32); + print_to_ss((int) SC_UserPwRetryCount); + print_to_ss((int) SC_AdminPwRetryCount); + print_to_ss((int) SD_Card_ManufacturingYear_u8); + print_to_ss((int) SD_Card_ManufacturingMonth_u8); + print_to_ss( SD_Card_OEM_u16); + print_to_ss( SD_WriteSpeed_u16); + print_to_ss((int) SD_Card_Manufacturer_u8); + return ss.str(); + } + + } __packed; + + typedef Transaction + CommandTransaction; + }; + + } + } +} + +#undef print_to_ss +#pragma pack (pop) + +#endif -- cgit v1.2.3 From b22b36f89e8924bd5eeef1105ce74a2df4ba02bd Mon Sep 17 00:00:00 2001 From: David Seifert Date: Sun, 11 Mar 2018 11:31:57 +0100 Subject: Allow overriding of udev rules dir --- CMakeLists.txt | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 43250b9..05e20d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,20 +121,22 @@ install (TARGETS nitrokey DESTINATION ${CMAKE_INSTALL_LIBDIR}) IF(NOT WIN32) # Install Nitrokey udev rules - set(PKG_GET_UDEV_DIR ${PKG_CONFIG_EXECUTABLE} --variable=udevdir udev) - execute_process(COMMAND ${PKG_GET_UDEV_DIR} RESULT_VARIABLE ERR OUTPUT_VARIABLE UDEV_MAIN_DIR OUTPUT_STRIP_TRAILING_WHITESPACE) - IF(${ERR}) - set(UDEV_MAIN_DIR "lib/udev/rules.d") - ELSE() - set(UDEV_MAIN_DIR "${UDEV_MAIN_DIR}/rules.d") + IF(NOT DEFINED CMAKE_INSTALL_UDEVRULESDIR) + set(PKG_GET_UDEV_DIR ${PKG_CONFIG_EXECUTABLE} --variable=udevdir udev) + execute_process(COMMAND ${PKG_GET_UDEV_DIR} RESULT_VARIABLE ERR OUTPUT_VARIABLE CMAKE_INSTALL_UDEVRULESDIR OUTPUT_STRIP_TRAILING_WHITESPACE) + IF(${ERR}) + set(CMAKE_INSTALL_UDEVRULESDIR "lib/udev/rules.d") + ELSE() + set(CMAKE_INSTALL_UDEVRULESDIR "${CMAKE_INSTALL_UDEVRULESDIR}/rules.d") + ENDIF() + string(REGEX REPLACE "^/" "" CMAKE_INSTALL_UDEVRULESDIR "${CMAKE_INSTALL_UDEVRULESDIR}") + string(REGEX REPLACE "^usr/" "" CMAKE_INSTALL_UDEVRULESDIR "${CMAKE_INSTALL_UDEVRULESDIR}") # usual prefix is usr/local + message(STATUS "Setting udev rules dir to ${CMAKE_INSTALL_UDEVRULESDIR}") ENDIF() - string(REGEX REPLACE "^/" "" UDEV_MAIN_DIR "${UDEV_MAIN_DIR}") - string(REGEX REPLACE "^usr/" "" UDEV_MAIN_DIR "${UDEV_MAIN_DIR}") # usual prefix is usr/local - message(STATUS "Setting udev rules dir to ${UDEV_MAIN_DIR}") install(FILES ${CMAKE_SOURCE_DIR}/data/41-nitrokey.rules - DESTINATION ${UDEV_MAIN_DIR} + DESTINATION ${CMAKE_INSTALL_UDEVRULESDIR} ) ENDIF() -- cgit v1.2.3