diff options
author | Robin Krahl <robin.krahl@ireas.org> | 2018-12-10 12:42:48 +0000 |
---|---|---|
committer | Robin Krahl <robin.krahl@ireas.org> | 2018-12-10 13:46:42 +0100 |
commit | 4615f5ecf96ef4637d814a4dfeab9c404b4a3667 (patch) | |
tree | 5bd65c78c1c913d44e8917c29e91895a9de450f6 /libnitrokey-v3.4/libnitrokey | |
parent | b126c5ba1e5a9f00859868d75900043d02a0031c (diff) | |
download | nitrokey-sys-rs-4615f5ecf96ef4637d814a4dfeab9c404b4a3667.tar.gz nitrokey-sys-rs-4615f5ecf96ef4637d814a4dfeab9c404b4a3667.tar.bz2 |
Update to libnitrokey v3.4v3.4.0
Besides the changes listed in the changelog, this patch also changes the
build system to be able to generate the version.cc file containing the
library version.
Diffstat (limited to 'libnitrokey-v3.4/libnitrokey')
19 files changed, 4022 insertions, 0 deletions
diff --git a/libnitrokey-v3.4/libnitrokey/CommandFailedException.h b/libnitrokey-v3.4/libnitrokey/CommandFailedException.h new file mode 100644 index 0000000..32bd6b7 --- /dev/null +++ b/libnitrokey-v3.4/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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#ifndef LIBNITROKEY_COMMANDFAILEDEXCEPTION_H +#define LIBNITROKEY_COMMANDFAILEDEXCEPTION_H + +#include <exception> +#include <cstdint> +#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<uint8_t>(cs::timestamp_warning); + } + + bool reason_AES_not_initialized() const throw(){ + return last_command_status == static_cast<uint8_t>(cs::AES_dec_failed); + } + + bool reason_not_authorized() const throw(){ + return last_command_status == static_cast<uint8_t>(cs::not_authorized); + } + + bool reason_slot_not_programmed() const throw(){ + return last_command_status == static_cast<uint8_t>(cs::slot_not_programmed); + } + + bool reason_wrong_password() const throw(){ + return last_command_status == static_cast<uint8_t>(cs::wrong_password); + } + + bool reason_smartcard_busy() const throw(){ + return last_command_status == static_cast<uint8_t>(cs2::smartcard_error); + } + +}; + + +#endif //LIBNITROKEY_COMMANDFAILEDEXCEPTION_H diff --git a/libnitrokey-v3.4/libnitrokey/DeviceCommunicationExceptions.h b/libnitrokey-v3.4/libnitrokey/DeviceCommunicationExceptions.h new file mode 100644 index 0000000..f710d0b --- /dev/null +++ b/libnitrokey-v3.4/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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + + +#ifndef LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H +#define LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H + +#include <atomic> +#include <exception> +#include <stdexcept> +#include <string> + + +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-v3.4/libnitrokey/LibraryException.h b/libnitrokey-v3.4/libnitrokey/LibraryException.h new file mode 100644 index 0000000..3b9d177 --- /dev/null +++ b/libnitrokey-v3.4/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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#ifndef LIBNITROKEY_LIBRARYEXCEPTION_H +#define LIBNITROKEY_LIBRARYEXCEPTION_H + +#include <exception> +#include <cstdint> +#include <string> +#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-v3.4/libnitrokey/LongOperationInProgressException.h b/libnitrokey-v3.4/libnitrokey/LongOperationInProgressException.h new file mode 100644 index 0000000..865d6b5 --- /dev/null +++ b/libnitrokey-v3.4/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 <http://www.gnu.org/licenses/>. + * + * 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-v3.4/libnitrokey/NitrokeyManager.h b/libnitrokey-v3.4/libnitrokey/NitrokeyManager.h new file mode 100644 index 0000000..d6e5df4 --- /dev/null +++ b/libnitrokey-v3.4/libnitrokey/NitrokeyManager.h @@ -0,0 +1,303 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * 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 <vector> +#include <memory> +#include <unordered_map> + +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 <NitrokeyManager> 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); + /** + * Set the device time used for TOTP to the given time. Contrary to + * {@code set_time(uint64_t)}, this command fails if {@code old_time} + * > {@code time} or if {@code old_time} is zero (where {@code + * old_time} is the current time on the device). + * + * @param time new device time as Unix timestamp (seconds since + * 1970-01-01) + */ + void set_time_soft(uint64_t time); + + [[deprecated("get_time is deprecated -- use set_time_soft instead")]] + 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<std::string> list_devices(); + std::vector<std::string> 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(device::DeviceModel 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(); + + char * get_totp_slot_name(uint8_t slot_number); + 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 <uint8_t> get_password_safe_slot_status(); + + uint8_t get_admin_retry_count(); + uint8_t get_user_retry_count(); + + void lock_device(); + + char * get_password_safe_slot_name(uint8_t slot_number); + char * get_password_safe_slot_password(uint8_t slot_number); + 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<uint8_t> 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); + + char * get_status_storage_as_string(); + stick20::DeviceConfigurationResponsePacket::ResponsePayload get_status_storage(); + + char * get_SD_usage_data_as_string(); + std::pair<uint8_t,uint8_t> get_SD_usage_data(); + + + int get_progress_bar_value(); + + ~NitrokeyManager(); + bool is_authorization_command_supported(); + bool is_320_OTP_secret_supported(); + + + template <typename S, typename A, typename T> + void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr<Device> device); + int get_minor_firmware_version(); + + explicit NitrokeyManager(); + void set_log_function(std::function<void(std::string)> log_function); + private: + + static shared_ptr <NitrokeyManager> _instance; + std::shared_ptr<Device> device; + std::string current_device_id; + public: + const string get_current_device_id() const; + + private: + std::unordered_map<std::string, shared_ptr<Device> > connected_devices; + std::unordered_map<std::string, shared_ptr<Device> > 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); + char * get_slot_name(uint8_t slot_number); + + template <typename ProCommand, PasswordKind StoKind> + 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(); + + /** + * Blink red and green LED alternatively and infinitely (until device is reconnected). + */ + void wink(); + + stick20::ProductionTest::ResponsePayload production_info(); + }; +} + + + +#endif //LIBNITROKEY_NITROKEYMANAGER_H diff --git a/libnitrokey-v3.4/libnitrokey/command.h b/libnitrokey-v3.4/libnitrokey/command.h new file mode 100644 index 0000000..6852bf0 --- /dev/null +++ b/libnitrokey-v3.4/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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#ifndef COMMAND_H +#define COMMAND_H +#include <string> +#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<CommandID cmd_id> + class Command : semantics::non_constructible { + public: + constexpr static CommandID command_id() { return cmd_id; } + + template<typename T> + 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<CommandID cmd_id, PasswordKind Tpassword_kind = PasswordKind::User, int password_length = 20> + class PasswordCommand : public Command<cmd_id> { + 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<cmd_id>::command_id(), struct CommandPayload, struct EmptyPayload> + // CommandTransaction; + using CommandTransaction = Transaction<cmd_id, CommandPayload, EmptyPayload>; + //using CommandTransaction = Transaction<_command_id(), CommandPayload, EmptyPayload>; + + }; + } + } +} + +#endif diff --git a/libnitrokey-v3.4/libnitrokey/command_id.h b/libnitrokey-v3.4/libnitrokey/command_id.h new file mode 100644 index 0000000..eb0d450 --- /dev/null +++ b/libnitrokey-v3.4/libnitrokey/command_id.h @@ -0,0 +1,154 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#ifndef COMMAND_ID_H +#define COMMAND_ID_H +#include <stdint.h> + +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, + //v0.52+ + WINK = 0x20 + 33, + + 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-v3.4/libnitrokey/cxx_semantics.h b/libnitrokey-v3.4/libnitrokey/cxx_semantics.h new file mode 100644 index 0000000..36ed142 --- /dev/null +++ b/libnitrokey-v3.4/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 <http://www.gnu.org/licenses/>. + * + * 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-v3.4/libnitrokey/deprecated.h b/libnitrokey-v3.4/libnitrokey/deprecated.h new file mode 100644 index 0000000..5a83288 --- /dev/null +++ b/libnitrokey-v3.4/libnitrokey/deprecated.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + + +#ifndef LIBNITROKEY_DEPRECATED_H +#define LIBNITROKEY_DEPRECATED_H + +#if defined(__GNUC__) || defined(__clang__) +#define DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED __declspec(deprecated) +#else +#pragma message("WARNING: DEPRECATED macro is not defined for this compiler") +#define DEPRECATED +#endif + +#endif //LIBNITROKEY_DEPRECATED_H diff --git a/libnitrokey-v3.4/libnitrokey/device.h b/libnitrokey-v3.4/libnitrokey/device.h new file mode 100644 index 0000000..f6d2380 --- /dev/null +++ b/libnitrokey-v3.4/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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#ifndef DEVICE_H +#define DEVICE_H +#include <chrono> +#include "hidapi/hidapi.h" +#include <cstdint> +#include <string> +#include <vector> + +#define HID_REPORT_SIZE 65 + +#include <atomic> + +namespace nitrokey { +namespace device { + using namespace std::chrono_literals; + using std::chrono::milliseconds; + + struct EnumClassHash + { + template <typename T> + std::size_t operator()(T t) const + { + return static_cast<std::size_t>(t); + } + }; + +enum class DeviceModel{ + PRO, + STORAGE +}; + +#include <atomic> + +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<std::string> 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<uint8_t>(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<uint8_t> 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::atomic<hid_device *>mp_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-v3.4/libnitrokey/device_proto.h b/libnitrokey-v3.4/libnitrokey/device_proto.h new file mode 100644 index 0000000..45a6c16 --- /dev/null +++ b/libnitrokey-v3.4/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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#ifndef DEVICE_PROTO_H +#define DEVICE_PROTO_H + +#include <utility> +#include <thread> +#include <type_traits> +#include <stdexcept> +#include <string> +// a local version for compatibility with Windows +#include <stdint.h> +#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 <mutex> +#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<CommandID cmd_id, typename Payload> + 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<cmd_id, decltype(*this)>::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<CommandID cmd_id, typename ResponsePayload> + 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<cmd_id, decltype(*this)>::dissect(*this); + } + } __packed; + + struct EmptyPayload { + bool isValid() const { return true; } + + std::string dissect() const { return std::string("Empty Payload."); } + } __packed; + + template<typename command_packet, typename response_payload> + 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<CommandID cmd_id, typename command_payload, typename response_payload> + 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<cmd_id, CommandPayload> OutgoingPacket; + typedef struct DeviceResponse<cmd_id, ResponsePayload> ResponsePacket; +#pragma pack (pop) + + static_assert(std::is_pod<OutgoingPacket>::value, + "outgoingpacket must be a pod type"); + static_assert(std::is_pod<ResponsePacket>::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<typename T> + static void clear_packet(T &st) { + bzero(&st, sizeof(st)); + } + + static ClearingProxy<ResponsePacket, response_payload> run(std::shared_ptr<device::Device> dev, + const command_payload &payload) { + using namespace ::nitrokey::device; + using namespace ::nitrokey::log; + using namespace std::chrono_literals; + + std::lock_guard<std::mutex> 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<std::string>(outp), Loglevel::DEBUG); + LOG(std::string("=> ") + std::string(commandid_to_string(static_cast<CommandID>(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<uint8_t>(stick10::command_status::ok); + switch (static_cast<stick20::device_status>(resp.storage_status.device_status)) { + case stick20::device_status::idle : + case stick20::device_status::ok: + resp.device_status = static_cast<uint8_t>(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<uint8_t>(stick10::device_status::busy); + break; + case stick20::device_status::wrong_password: + resp.last_command_status = static_cast<uint8_t>(stick10::command_status::wrong_password); + resp.device_status = static_cast<uint8_t>(stick10::device_status::ok); + break; + case stick20::device_status::no_user_password_unlock: + resp.last_command_status = static_cast<uint8_t>(stick10::command_status::AES_dec_failed); + resp.device_status = static_cast<uint8_t>(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<uint8_t>(stick10::device_status::ok) && + CRC_equal_awaited && resp.isValid()){ + successful_communication = true; + break; + } + if (resp.device_status == static_cast<uint8_t>(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<uint8_t>(stick10::device_status::busy) && + static_cast<stick20::device_status>(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<std::string>(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<CommandID>(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<CommandID>(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<std::string>(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<uint8_t>(stick10::device_status::busy) && + static_cast<stick20::device_status>(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<uint8_t>(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<CommandID>(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<ResponsePacket, response_payload> run(std::shared_ptr<device::Device> dev) { + command_payload empty_payload; + return run(dev, empty_payload); + } + }; + } +} +#endif diff --git a/libnitrokey-v3.4/libnitrokey/dissect.h b/libnitrokey-v3.4/libnitrokey/dissect.h new file mode 100644 index 0000000..690b5b7 --- /dev/null +++ b/libnitrokey-v3.4/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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +/* + * Protocol packet dissection + */ +#ifndef DISSECT_H +#define DISSECT_H +#include <string> +#include <sstream> +#include <iomanip> +#include "misc.h" +#include "cxx_semantics.h" +#include "command_id.h" +#include "device_proto.h" + +namespace nitrokey { +namespace proto { + +template <CommandID id, class HIDPacket> +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 <CommandID id, class HIDPacket> +class ResponseDissector : semantics::non_constructible { + public: + static std::string status_translate_device(int status){ + auto enum_status = static_cast<proto::stick10::device_status>(status); + switch (enum_status){ + case stick10::device_status::ok: return "OK"; + case stick10::device_status::busy: return "BUSY"; + case stick10::device_status::error: return "ERROR"; + case stick10::device_status::received_report: return "RECEIVED_REPORT"; + } + return std::string("UNKNOWN: ") + std::to_string(status); + } + + static std::string to_upper(std::string str){ + for (auto & c: str) c = toupper(c); + return str; + } + static std::string status_translate_command(int status){ + auto enum_status = static_cast<proto::stick10::command_status >(status); + switch (enum_status) { +#define p(X) case X: return to_upper(std::string(#X)); + p(stick10::command_status::ok) + p(stick10::command_status::wrong_CRC) + p(stick10::command_status::wrong_slot) + p(stick10::command_status::slot_not_programmed) + p(stick10::command_status::wrong_password) + p(stick10::command_status::not_authorized) + p(stick10::command_status::timestamp_warning) + p(stick10::command_status::no_name_error) + p(stick10::command_status::not_supported) + p(stick10::command_status::unknown_command) + p(stick10::command_status::AES_dec_failed) +#undef p + } + return std::string("UNKNOWN: ") + std::to_string(status); + } + + static std::string dissect(const HIDPacket &pod) { + std::stringstream out; + + // FIXME use values from firmware (possibly generate separate + // header automatically) + +#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<int>(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-v3.4/libnitrokey/hidapi/hidapi.h b/libnitrokey-v3.4/libnitrokey/hidapi/hidapi.h new file mode 100644 index 0000000..e5bc2dc --- /dev/null +++ b/libnitrokey-v3.4/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 <wchar.h> + +#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-v3.4/libnitrokey/log.h b/libnitrokey-v3.4/libnitrokey/log.h new file mode 100644 index 0000000..2a64bef --- /dev/null +++ b/libnitrokey-v3.4/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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#ifndef LOG_H +#define LOG_H + +#include <string> +#include <functional> + +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<void(std::string)>; + 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-v3.4/libnitrokey/misc.h b/libnitrokey-v3.4/libnitrokey/misc.h new file mode 100644 index 0000000..88254dd --- /dev/null +++ b/libnitrokey-v3.4/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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + + +#ifndef MISC_H +#define MISC_H +#include <stdio.h> +#include <string> +#include <vector> +#include <string.h> +#include "log.h" +#include "LibraryException.h" +#include <sstream> +#include <iomanip> + + +namespace nitrokey { +namespace misc { + + template<typename T> + 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 <typename T> + 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> +typename T::CommandPayload get_payload(){ + //Create, initialize and return by value command payload + typename T::CommandPayload st; + bzero(&st, sizeof(st)); + return st; +} + + template<typename CMDTYPE, typename Tdev> + void execute_password_command(Tdev &stick, const char *password) { + auto p = get_payload<CMDTYPE>(); + 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<uint8_t> hex_string_to_byte(const char* hexString); +} +} + +#endif diff --git a/libnitrokey-v3.4/libnitrokey/stick10_commands.h b/libnitrokey-v3.4/libnitrokey/stick10_commands.h new file mode 100644 index 0000000..f2ffba2 --- /dev/null +++ b/libnitrokey-v3.4/libnitrokey/stick10_commands.h @@ -0,0 +1,889 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#ifndef STICK10_COMMANDS_H +#define STICK10_COMMANDS_H + +#include <bitset> +#include <iomanip> +#include <string> +#include <sstream> +#include <stdint.h> +#include "device_proto.h" +#include "command.h" + +#pragma pack (push,1) + +namespace nitrokey { +namespace proto { + + + +/* + * Stick10 protocol definition + */ +namespace stick10 { +class GetSlotName : public Command<CommandID::READ_SLOT_NAME> { + 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<command_id(), struct CommandPayload, + struct ResponsePayload> CommandTransaction; +}; + +class EraseSlot : Command<CommandID::ERASE_SLOT> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class SetTime : Command<CommandID::SET_TIME> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + + +class WriteToHOTPSlot : Command<CommandID::WRITE_TO_SLOT> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class WriteToTOTPSlot : Command<CommandID::WRITE_TO_SLOT> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class GetTOTP : Command<CommandID::GET_CODE> { + 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<command_id(), struct CommandPayload, struct ResponsePayload> + CommandTransaction; +}; + +class GetHOTP : Command<CommandID::GET_CODE> { + 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<command_id(), struct CommandPayload, struct ResponsePayload> + CommandTransaction; +}; + +class ReadSlot : Command<CommandID::READ_SLOT> { + 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<command_id(), struct CommandPayload, + struct ResponsePayload> CommandTransaction; +}; + +class GetStatus : Command<CommandID::GET_STATUS> { + public: + struct ResponsePayload { + union { + uint16_t firmware_version; + struct { + uint8_t minor; + uint8_t major; + } firmware_version_st; + }; + union{ + uint8_t card_serial[4]; + uint32_t card_serial_u32; + } __packed; + union { + uint8_t general_config[5]; + struct{ + uint8_t numlock; /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */ + uint8_t capslock; /** same as numlock */ + uint8_t scrolllock; /** same as numlock */ + uint8_t enable_user_password; + uint8_t delete_user_password; /* unused */ + } __packed; + } __packed; + + static constexpr uint8_t special_HOTP_slots = 2; + bool isValid() const { return numlock < special_HOTP_slots && capslock < special_HOTP_slots + && scrolllock < special_HOTP_slots && enable_user_password < 2; } + + std::string get_card_serial_hex() const { + return nitrokey::misc::toHex(card_serial_u32); + } + + std::string dissect() const { + std::stringstream ss; + ss << "firmware_version:\t" + << "[" << firmware_version << "]" << "\t" + << ::nitrokey::misc::hexdump( + (const uint8_t *)(&firmware_version), sizeof firmware_version, false); + ss << "card_serial_u32:\t" << std::hex << card_serial_u32 << std::endl; + ss << "card_serial:\t" + << ::nitrokey::misc::hexdump((const uint8_t *)(card_serial), + sizeof card_serial, false); + ss << "general_config:\t" + << ::nitrokey::misc::hexdump((const uint8_t *)(general_config), + sizeof general_config, false); + ss << "numlock:\t" << (int)numlock << std::endl; + ss << "capslock:\t" << (int)capslock << std::endl; + ss << "scrolllock:\t" << (int)scrolllock << std::endl; + ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl; + ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl; + + return ss.str(); + } + } __packed; + + typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload> + CommandTransaction; +}; + +class GetPasswordRetryCount : Command<CommandID::GET_PASSWORD_RETRY_COUNT> { + 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<command_id(), struct EmptyPayload, struct ResponsePayload> + CommandTransaction; +}; + +class GetUserPasswordRetryCount + : Command<CommandID::GET_USER_PASSWORD_RETRY_COUNT> { + 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<command_id(), struct EmptyPayload, struct ResponsePayload> + CommandTransaction; +}; + + template <typename T, typename Q, int N> + void write_array(T &ss, Q (&arr)[N]){ + for (int i=0; i<N; i++){ + ss << std::hex << std::setfill('0') << std::setw(2) << (int)arr[i] << " "; + } + ss << std::endl; + }; + + +class GetPasswordSafeSlotStatus : Command<CommandID::GET_PW_SAFE_SLOT_STATUS> { + 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<command_id(), struct EmptyPayload, struct ResponsePayload> + CommandTransaction; +}; + +class GetPasswordSafeSlotName : Command<CommandID::GET_PW_SAFE_SLOT_NAME> { + 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<command_id(), struct CommandPayload, + struct ResponsePayload> CommandTransaction; +}; + +class GetPasswordSafeSlotPassword + : Command<CommandID::GET_PW_SAFE_SLOT_PASSWORD> { + 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<command_id(), struct CommandPayload, + struct ResponsePayload> CommandTransaction; +}; + +class GetPasswordSafeSlotLogin + : Command<CommandID::GET_PW_SAFE_SLOT_LOGINNAME> { + 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<command_id(), struct CommandPayload, + struct ResponsePayload> CommandTransaction; +}; + +class SetPasswordSafeSlotData : Command<CommandID::SET_PW_SAFE_SLOT_DATA_1> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class SetPasswordSafeSlotData2 : Command<CommandID::SET_PW_SAFE_SLOT_DATA_2> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class ErasePasswordSafeSlot : Command<CommandID::PW_SAFE_ERASE_SLOT> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class EnablePasswordSafe : Command<CommandID::PW_SAFE_ENABLE> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class PasswordSafeInitKey : Command<CommandID::PW_SAFE_INIT_KEY> { + /** + * never used in Nitrokey App + */ + public: + typedef Transaction<command_id(), struct EmptyPayload, struct EmptyPayload> + CommandTransaction; +}; + +class PasswordSafeSendSlotViaHID : Command<CommandID::PW_SAFE_SEND_DATA> { + /** + * 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +// TODO "Device::passwordSafeSendSlotDataViaHID" + +class WriteGeneralConfig : Command<CommandID::WRITE_CONFIG> { + public: + struct CommandPayload { + union{ + uint8_t config[5]; + struct{ + uint8_t numlock; /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */ + uint8_t capslock; /** same as numlock */ + uint8_t scrolllock; /** same as numlock */ + uint8_t enable_user_password; + uint8_t delete_user_password; + }; + }; + bool isValid() const { return numlock < 2 && capslock < 2 && scrolllock < 2 && enable_user_password < 2; } + + std::string dissect() const { + std::stringstream ss; + ss << "numlock:\t" << (int)numlock << std::endl; + ss << "capslock:\t" << (int)capslock << std::endl; + ss << "scrolllock:\t" << (int)scrolllock << std::endl; + ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl; + ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl; + return ss.str(); + } + } __packed; + + typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class FirstAuthenticate : Command<CommandID::FIRST_AUTHENTICATE> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class UserAuthenticate : Command<CommandID::USER_AUTHENTICATE> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class Authorize : Command<CommandID::AUTHORIZE> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class UserAuthorize : Command<CommandID::USER_AUTHORIZE> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class UnlockUserPassword : Command<CommandID::UNLOCK_USER_PASSWORD> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class ChangeUserPin : Command<CommandID::CHANGE_USER_PIN> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class IsAESSupported : Command<CommandID::DETECT_SC_AES> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + + +class ChangeAdminPin : Command<CommandID::CHANGE_ADMIN_PIN> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class LockDevice : Command<CommandID::LOCK_DEVICE> { + public: + typedef Transaction<command_id(), struct EmptyPayload, struct EmptyPayload> + CommandTransaction; +}; + +class FactoryReset : Command<CommandID::FACTORY_RESET> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; +}; + +class BuildAESKey : Command<CommandID::NEW_AES_KEY> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; + +}; + +} +} +} +#pragma pack (pop) +#endif diff --git a/libnitrokey-v3.4/libnitrokey/stick10_commands_0.8.h b/libnitrokey-v3.4/libnitrokey/stick10_commands_0.8.h new file mode 100644 index 0000000..9477890 --- /dev/null +++ b/libnitrokey-v3.4/libnitrokey/stick10_commands_0.8.h @@ -0,0 +1,348 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + + +#ifndef LIBNITROKEY_STICK10_COMMANDS_0_8_H +#define LIBNITROKEY_STICK10_COMMANDS_0_8_H + +#include <bitset> +#include <iomanip> +#include <string> +#include <sstream> +#include <cstdint> +#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<CommandID::ERASE_SLOT> { + public: + struct CommandPayload { + uint8_t slot_number; + uint8_t temporary_admin_password[25]; + + bool isValid() const { return !(slot_number & 0xF0); } + std::string dissect() const { + std::stringstream ss; + ss << "slot_number:\t" << (int)(slot_number) << std::endl; + hexdump_to_ss(temporary_admin_password); + return ss.str(); + } + } __packed; + + typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; + }; + + class SendOTPData : Command<CommandID::SEND_OTP_DATA> { + //admin auth + public: + struct CommandPayload { + uint8_t temporary_admin_password[25]; + uint8_t type; //S-secret, N-name + uint8_t id; //multiple reports for values longer than 30 bytes + uint8_t data[30]; //data, does not need null termination + + bool isValid() const { return true; } + + void setTypeName(){ + type = 'N'; + } + void setTypeSecret(){ + type = 'S'; + } + + std::string dissect() const { + std::stringstream ss; + 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<command_id(), struct CommandPayload, struct ResponsePayload> + CommandTransaction; + }; + + class WriteToOTPSlot : Command<CommandID::WRITE_TO_SLOT> { + //admin auth + public: + struct CommandPayload { + uint8_t temporary_admin_password[25]; + uint8_t slot_number; + union { + uint64_t slot_counter_or_interval; + uint8_t slot_counter_s[8]; + } __packed; + union { + uint8_t _slot_config; + struct { + bool use_8_digits : 1; + bool use_enter : 1; + bool use_tokenID : 1; + }; + }; + union { + uint8_t slot_token_id[13]; /** OATH Token Identifier */ + struct { /** @see https://openauthentication.org/token-specs/ */ + uint8_t omp[2]; + uint8_t tt[2]; + uint8_t mui[8]; + uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805 + } slot_token_fields; + }; + + bool isValid() const { return true; } + + std::string dissect() const { + std::stringstream ss; + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; + }; + + class GetHOTP : Command<CommandID::GET_CODE> { + public: + struct CommandPayload { + uint8_t slot_number; + struct { + uint64_t challenge; //@unused + uint64_t last_totp_time; //@unused + uint8_t last_interval; //@unused + } __packed _unused; + uint8_t temporary_user_password[25]; + + bool isValid() const { return (slot_number & 0xF0); } + std::string dissect() const { + std::stringstream ss; + 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<command_id(), struct CommandPayload, struct ResponsePayload> + CommandTransaction; + }; + + + class GetTOTP : Command<CommandID::GET_CODE> { + //user auth + public: + struct CommandPayload { + uint8_t slot_number; + uint64_t challenge; //@unused + uint64_t last_totp_time; //@unused + uint8_t last_interval; //@unused + uint8_t temporary_user_password[25]; + + bool isValid() const { return !(slot_number & 0xF0); } + std::string dissect() const { + std::stringstream ss; + 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<command_id(), struct CommandPayload, struct ResponsePayload> + CommandTransaction; + }; + + + class WriteGeneralConfig : Command<CommandID::WRITE_CONFIG> { + //admin auth + public: + struct CommandPayload { + union{ + uint8_t config[5]; + struct{ + uint8_t numlock; /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */ + uint8_t capslock; /** same as numlock */ + uint8_t scrolllock; /** same as numlock */ + uint8_t enable_user_password; + uint8_t delete_user_password; + }; + }; + uint8_t temporary_admin_password[25]; + + static constexpr uint8_t special_HOTP_slots = 3; + bool isValid() const { return numlock < special_HOTP_slots && capslock < special_HOTP_slots + && scrolllock < special_HOTP_slots && enable_user_password < 2; } + + std::string dissect() const { + std::stringstream ss; + ss << "numlock:\t" << (int)numlock << std::endl; + ss << "capslock:\t" << (int)capslock << std::endl; + ss << "scrolllock:\t" << (int)scrolllock << std::endl; + ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl; + ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl; + return ss.str(); + } + } __packed; + + typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; + }; + } + } +} +#pragma pack (pop) + +#endif //LIBNITROKEY_STICK10_COMMANDS_0_8_H diff --git a/libnitrokey-v3.4/libnitrokey/stick20_commands.h b/libnitrokey-v3.4/libnitrokey/stick20_commands.h new file mode 100644 index 0000000..7efa1b6 --- /dev/null +++ b/libnitrokey-v3.4/libnitrokey/stick20_commands.h @@ -0,0 +1,394 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#ifndef STICK20_COMMANDS_H +#define STICK20_COMMANDS_H + + + +#include <cstdint> +#include "command.h" +#include <string> +#include <sstream> +#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<CommandID::SEND_PASSWORD, PasswordKind::Admin> {}; + class ChangeAdminUserPin20New : + public PasswordCommand<CommandID::SEND_NEW_PASSWORD, PasswordKind::Admin> {}; + class UnlockUserPin : + public PasswordCommand<CommandID::UNLOCK_USER_PASSWORD, PasswordKind::Admin> {}; + + class EnableEncryptedPartition : public PasswordCommand<CommandID::ENABLE_CRYPTED_PARI> {}; + class EnableHiddenEncryptedPartition : public PasswordCommand<CommandID::ENABLE_HIDDEN_CRYPTED_PARI> {}; + + class SetUnencryptedVolumeReadOnlyAdmin : + public PasswordCommand<CommandID::ENABLE_ADMIN_READONLY_UNCRYPTED_LUN, PasswordKind::Admin> {}; + class SetUnencryptedVolumeReadWriteAdmin : + public PasswordCommand<CommandID::ENABLE_ADMIN_READWRITE_UNCRYPTED_LUN, PasswordKind::Admin> {}; + class SetEncryptedVolumeReadOnly : + public PasswordCommand<CommandID::ENABLE_ADMIN_READONLY_ENCRYPTED_LUN, PasswordKind::Admin> {}; + class SetEncryptedVolumeReadWrite : + public PasswordCommand<CommandID::ENABLE_ADMIN_READWRITE_ENCRYPTED_LUN, PasswordKind::Admin> {}; + + //FIXME the volume disabling commands do not need password + class DisableEncryptedPartition : public PasswordCommand<CommandID::DISABLE_CRYPTED_PARI> {}; + class DisableHiddenEncryptedPartition : public PasswordCommand<CommandID::DISABLE_HIDDEN_CRYPTED_PARI> {}; + + class EnableFirmwareUpdate : public PasswordCommand<CommandID::ENABLE_FIRMWARE_UPDATE> {}; + + class ChangeUpdatePassword : Command<CommandID::CHANGE_UPDATE_PIN> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; + }; + + class ExportFirmware : public PasswordCommand<CommandID::EXPORT_FIRMWARE_TO_FILE> {}; + + class CreateNewKeys : + public PasswordCommand<CommandID::GENERATE_NEW_KEYS, PasswordKind::AdminPrefixed, 30> {}; + + + class FillSDCardWithRandomChars : Command<CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS> { + 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<uint8_t>(ChosenVolumes::encrypted_volume); + } + + } __packed; + + typedef Transaction<Command<CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS>::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<CommandID::SEND_STARTUP> { + 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::seconds> ( + std::chrono::system_clock::now().time_since_epoch()).count(); + } + }__packed; + + using ResponsePayload = DeviceConfigurationResponsePacket::ResponsePayload; + + typedef Transaction<command_id(), struct CommandPayload, ResponsePayload> + CommandTransaction; + }; + + +// TODO fix original nomenclature + class SendSetReadonlyToUncryptedVolume : public PasswordCommand<CommandID::ENABLE_READONLY_UNCRYPTED_LUN> {}; + class SendSetReadwriteToUncryptedVolume : public PasswordCommand<CommandID::ENABLE_READWRITE_UNCRYPTED_LUN> {}; + class SendClearNewSdCardFound : public PasswordCommand<CommandID::CLEAR_NEW_SD_CARD_FOUND> {}; + + class GetDeviceStatus : Command<CommandID::GET_DEVICE_STATUS> { + public: + using ResponsePayload = DeviceConfigurationResponsePacket::ResponsePayload; + + typedef Transaction<command_id(), struct EmptyPayload, ResponsePayload> + CommandTransaction; + }; + + class Wink : Command<CommandID::WINK> { + public: + typedef Transaction<command_id(), struct EmptyPayload, struct EmptyPayload> + CommandTransaction; + }; + + class CheckSmartcardUsage : Command<CommandID::CHECK_SMARTCARD_USAGE> { + public: + typedef Transaction<command_id(), struct EmptyPayload, EmptyPayload> + CommandTransaction; + }; + + class GetSDCardOccupancy : Command<CommandID::SD_CARD_HIGH_WATERMARK> { + 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<command_id(), struct EmptyPayload, struct ResponsePayload> + CommandTransaction; + }; + + + class SetupHiddenVolume : Command<CommandID::SEND_HIDDEN_VOLUME_SETUP> { + 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<command_id(), struct CommandPayload, struct EmptyPayload> + CommandTransaction; + }; + + +//disable this command for now +// class LockFirmware : public PasswordCommand<CommandID::SEND_LOCK_STICK_HARDWARE> {}; + + class ProductionTest : Command<CommandID::PRODUCTION_TEST> { + 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<command_id(), struct EmptyPayload, struct ResponsePayload> + CommandTransaction; + }; + + } + } +} + +#undef print_to_ss +#pragma pack (pop) + +#endif diff --git a/libnitrokey-v3.4/libnitrokey/version.h b/libnitrokey-v3.4/libnitrokey/version.h new file mode 100644 index 0000000..6547af0 --- /dev/null +++ b/libnitrokey-v3.4/libnitrokey/version.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#ifndef LIBNITROKEY_VERSION_H +#define LIBNITROKEY_VERSION_H + +namespace nitrokey { + unsigned int get_major_library_version(); + + unsigned int get_minor_library_version(); + + const char* get_library_version(); +} + +#endif |