diff options
Diffstat (limited to 'nitrokey-sys/libnitrokey-v3.4.1/libnitrokey')
19 files changed, 4022 insertions, 0 deletions
diff --git a/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/CommandFailedException.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/CommandFailedException.h new file mode 100644 index 0000000..32bd6b7 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/DeviceCommunicationExceptions.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/DeviceCommunicationExceptions.h new file mode 100644 index 0000000..f710d0b --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/LibraryException.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/LibraryException.h new file mode 100644 index 0000000..3b9d177 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/LongOperationInProgressException.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/LongOperationInProgressException.h new file mode 100644 index 0000000..865d6b5 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/NitrokeyManager.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/NitrokeyManager.h new file mode 100644 index 0000000..d6e5df4 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/command.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/command.h new file mode 100644 index 0000000..6852bf0 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/command_id.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/command_id.h new file mode 100644 index 0000000..eb0d450 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/cxx_semantics.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/cxx_semantics.h new file mode 100644 index 0000000..36ed142 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/deprecated.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/deprecated.h new file mode 100644 index 0000000..5a83288 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/device.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/device.h new file mode 100644 index 0000000..f6d2380 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/device_proto.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/device_proto.h new file mode 100644 index 0000000..45a6c16 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/dissect.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/dissect.h new file mode 100644 index 0000000..690b5b7 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/hidapi/hidapi.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/hidapi/hidapi.h new file mode 100644 index 0000000..e5bc2dc --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/log.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/log.h new file mode 100644 index 0000000..2a64bef --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/misc.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/misc.h new file mode 100644 index 0000000..88254dd --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/stick10_commands.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/stick10_commands.h new file mode 100644 index 0000000..f2ffba2 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/stick10_commands_0.8.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/stick10_commands_0.8.h new file mode 100644 index 0000000..9477890 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/stick20_commands.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/stick20_commands.h new file mode 100644 index 0000000..7efa1b6 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/version.h b/nitrokey-sys/libnitrokey-v3.4.1/libnitrokey/version.h new file mode 100644 index 0000000..6547af0 --- /dev/null +++ b/nitrokey-sys/libnitrokey-v3.4.1/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  | 
