diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/command.h | 23 | ||||
| -rw-r--r-- | include/command_id.h | 85 | ||||
| -rw-r--r-- | include/crc32.h | 32 | ||||
| -rw-r--r-- | include/cxx_semantics.h | 6 | ||||
| -rw-r--r-- | include/device.h | 80 | ||||
| -rw-r--r-- | include/device_proto.h | 1170 | ||||
| -rw-r--r-- | include/dissect.h | 82 | ||||
| -rw-r--r-- | include/inttypes.h | 522 | ||||
| -rw-r--r-- | include/log.h | 50 | ||||
| -rw-r--r-- | include/misc.h | 14 | ||||
| -rw-r--r-- | include/stick10_commands.h | 588 | ||||
| -rw-r--r-- | include/stick20_commands.h | 233 | 
12 files changed, 1814 insertions, 1071 deletions
| diff --git a/include/command.h b/include/command.h new file mode 100644 index 0000000..715902d --- /dev/null +++ b/include/command.h @@ -0,0 +1,23 @@ +#ifndef COMMAND_H +#define COMMAND_H +#include <string> +#include "command_id.h" +#include "cxx_semantics.h" + +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> +  static std::string dissect(const T &) { +    return std::string("Payload dissection is unavailable"); +  } +}; +} +} + +#endif diff --git a/include/command_id.h b/include/command_id.h new file mode 100644 index 0000000..37aa5d2 --- /dev/null +++ b/include/command_id.h @@ -0,0 +1,85 @@ +#ifndef COMMAND_ID_H +#define COMMAND_ID_H +#include "inttypes.h" + +namespace nitrokey { +namespace proto { + +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, + +  ENABLE_CRYPTED_PARI = 0x20, +  DISABLE_CRYPTED_PARI, +  ENABLE_HIDDEN_CRYPTED_PARI, +  DISABLE_HIDDEN_CRYPTED_PARI, +  ENABLE_FIRMWARE_UPDATE, +  EXPORT_FIRMWARE_TO_FILE, +  GENERATE_NEW_KEYS, +  FILL_SD_CARD_WITH_RANDOM_CHARS, + +  WRITE_STATUS_DATA, +  ENABLE_READONLY_UNCRYPTED_LUN, +  ENABLE_READWRITE_UNCRYPTED_LUN, + +  SEND_PASSWORD_MATRIX, +  SEND_PASSWORD_MATRIX_PINDATA, +  SEND_PASSWORD_MATRIX_SETUP, + +  GET_DEVICE_STATUS, +  SEND_DEVICE_STATUS, + +  SEND_HIDDEN_VOLUME_PASSWORD, +  SEND_HIDDEN_VOLUME_SETUP, +  SEND_PASSWORD, +  SEND_NEW_PASSWORD, +  CLEAR_NEW_SD_CARD_FOUND, + +  SEND_STARTUP, +  SEND_CLEAR_STICK_KEYS_NOT_INITIATED, +  SEND_LOCK_STICK_HARDWARE, + +  PRODUCTION_TEST, +  SEND_DEBUG_DATA, + +  CHANGE_UPDATE_PIN, + +  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, +  PW_SAFE_SEND_DATA = 0x69, +  SD_CARD_HIGH_WATERMARK = 0x70, +  DETECT_SC_AES = 0x6a, +  NEW_AES_KEY = 0x6b +}; + +const char *commandid_to_string(CommandID id); +} +} +#endif diff --git a/include/crc32.h b/include/crc32.h deleted file mode 100644 index b0e16ff..0000000 --- a/include/crc32.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Author: Copyright (C) Andrzej Surowiec 2012 - * - * - * This file is part of Nitrokey. - * - * Nitrokey is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * Nitrokey 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 General Public License - * along with Nitrokey. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef CRC32_H -#define CRC32_H - -#ifdef _MSC_VER -#define uint32_t unsigned long -#else -#include "inttypes.h" -#endif - -uint32_t Crc32 (uint32_t Crc, uint32_t Data); - -#endif // CRC32_H diff --git a/include/cxx_semantics.h b/include/cxx_semantics.h index f5d3dca..b846317 100644 --- a/include/cxx_semantics.h +++ b/include/cxx_semantics.h @@ -7,9 +7,9 @@   *	There's no need to include Boost for a simple subset this project needs.   */  namespace semantics { -	class non_constructible { -		non_constructible() {} -	}; +class non_constructible { +  non_constructible() {} +};  }  #endif diff --git a/include/device.h b/include/device.h index b2d83b5..dc7832d 100644 --- a/include/device.h +++ b/include/device.h @@ -8,58 +8,66 @@  // TODO !! SEMAPHORE +namespace nitrokey {  namespace device { -enum class CommError  -{ -	ERR_NO_ERROR = 0, -	ERR_NOT_CONNECTED = -1, -	ERR_WRONG_RESPONSE_CRC = -2, -	ERR_SENDING = -3, -	ERR_STATUS_NOT_OK = -4 + +enum class CommError { +  ERR_NO_ERROR = 0, +  ERR_NOT_CONNECTED = -1, +  ERR_WRONG_RESPONSE_CRC = -2, +  ERR_SENDING = -3, +  ERR_STATUS_NOT_OK = -4  };  class Device { -public: -	Device(); + public: +  Device(); + +  // lack of device is not actually an error, +  // so it doesn't throw +  virtual bool connect(); +  virtual bool disconnect(); -	// lack of device is not actually an error, -	// so it doesn't throw -	virtual bool connect();  +  /* +   *	Sends packet of HID_REPORT_SIZE. +   */ +  virtual CommError send(const void *packet); -	/* -	 *	Sends packet of HID_REPORT_SIZE. -	 */ -	virtual CommError send(const void *packet); +  /* +   *	Gets packet of HID_REPORT_SIZE. +   *	Can sleep. See below. +   */ +  virtual CommError recv(void *packet); -	/* -	 *	Gets packet of HID_REPORT_SIZE. -	 *	Can sleep. See below. -	 */ -	virtual CommError recv(void *packet); +  int get_retry_count() { return m_retry_count; } +  const; +  std::chrono::milliseconds get_retry_timeout() { return m_retry_timeout; } +  const; -protected: -	uint16_t m_vid; -	uint16_t m_pid; + protected: +  uint16_t m_vid; +  uint16_t m_pid; -	/* -	 *	While the project uses Signal11 portable HIDAPI -	 *	library, there's no way of doing it asynchronously, -	 *	hence polling. -	 */ -	int m_retry_count; -	std::chrono::milliseconds m_retry_timeout; +  /* +   *	While the project uses Signal11 portable HIDAPI +   *	library, there's no way of doing it asynchronously, +   *	hence polling. +   */ +  int m_retry_count; +  std::chrono::milliseconds m_retry_timeout; -	hid_device *mp_devhandle; +  hid_device *mp_devhandle;  };  class Stick10 : public Device { -public: -	Stick10(); + public: +  Stick10();  };  class Stick20 : public Device { -public: -	Stick20(); + public: +  Stick20();  };  } +}  #endif diff --git a/include/device_proto.h b/include/device_proto.h index fb1dd4e..e05a303 100644 --- a/include/device_proto.h +++ b/include/device_proto.h @@ -1,6 +1,7 @@  #ifndef DEVICE_PROTO_H  #define DEVICE_PROTO_H  #include <utility> +#include <thread>  #include <type_traits>  #include <stdexcept>  #include <string> @@ -9,7 +10,10 @@  #include "inttypes.h"  #include "cxx_semantics.h"  #include "device.h" -#include "utils/crc32.h" +#include "misc.h" +#include "log.h" +#include "command_id.h" +#include "dissect.h"  #define STICK20_UPDATE_MODE_VID 0x03EB  #define STICK20_UPDATE_MODE_PID 0x2FF1 @@ -20,99 +24,13 @@  #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 - -namespace device { -	class Device; -	enum class CommError; -} - -static inline uint32_t crc(const uint8_t *data, size_t size) { -	uint32_t crc = 0xffffffff; -	const uint32_t *pend = (const uint32_t *)(data + size); -	for (const uint32_t *p = (const uint32_t *)(data); p < pend; p++) -		crc = Crc32 (crc, *p); -	return crc; -} +#define PWS_SEND_PASSWORD 0 +#define PWS_SEND_LOGINNAME 1 +#define PWS_SEND_TAB 2 +#define PWS_SEND_CR 3 +namespace nitrokey {  namespace proto { -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, - -	ENABLE_CRYPTED_PARI = 0x20, -	DISABLE_CRYPTED_PARI, -	ENABLE_HIDDEN_CRYPTED_PARI, -	DISABLE_HIDDEN_CRYPTED_PARI, -	ENABLE_FIRMWARE_UPDATE, -	EXPORT_FIRMWARE_TO_FILE, -	GENERATE_NEW_KEYS, -	FILL_SD_CARD_WITH_RANDOM_CHARS, - -	WRITE_STATUS_DATA, -	ENABLE_READONLY_UNCRYPTED_LUN, -	ENABLE_READWRITE_UNCRYPTED_LUN, - -	SEND_PASSWORD_MATRIX, -	SEND_PASSWORD_MATRIX_PINDATA, -	SEND_PASSWORD_MATRIX_SETUP, - -	GET_DEVICE_STATUS, -	SEND_DEVICE_STATUS, - -	SEND_HIDDEN_VOLUME_PASSWORD, -	SEND_HIDDEN_VOLUME_SETUP, -	SEND_PASSWORD, -	SEND_NEW_PASSWORD, -	CLEAR_NEW_SD_CARD_FOUND, - -	SEND_STARTUP, -	SEND_CLEAR_STICK_KEYS_NOT_INITIATED, -	SEND_LOCK_STICK_HARDWARE, - -	PRODUCTION_TEST, -	SEND_DEBUG_DATA, - -	CHANGE_UPDATE_PIN, - -	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, -	PW_SAFE_SEND_DATA          		= 0x69, -	SD_CARD_HIGH_WATERMARK     		= 0x70, -	DETECT_SC_AES              		= 0x6a, -	NEW_AES_KEY                		= 0x6b -}; -  /*   *	POD types for HID proto commands   *	Instances are meant to be __packed. @@ -125,39 +43,42 @@ enum class CommandID : uint8_t {   */  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 ::crc((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(); -	} +  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;  /* @@ -166,890 +87,139 @@ struct HIDReport {   *	command_id member in incoming HIDReport structure carries the command   *	type last used.   */ -template <typename ResponsePayload> +template <CommandID cmd_id, typename ResponsePayload>  struct DeviceResponse { -	uint8_t _zero; -	uint8_t device_status; -	uint8_t last_command_type; -	uint32_t last_command_crc; -	uint8_t	last_command_status; -	union { -		uint8_t _padding[HID_REPORT_SIZE - 12]; -		ResponsePayload payload; -	} __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 ::crc((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(); -	} +  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 - 12]; +    ResponsePayload payload; +  } __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 true; +  } + +  operator std::string() const { +    return ResponseDissector<cmd_id, decltype(*this)>::dissect(*this); +  }  } __packed;  struct EmptyPayload { -	uint8_t _data[]; +  uint8_t _data[]; + +  bool isValid() const { return true; } -	bool isValid() const { -		return true; -	} +  std::string dissect() const { return std::string("Empty Payload."); }  } __packed; -template<CommandID cmd_id, typename command_payload, -							typename response_payload> +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<ResponsePayload> ResponsePacket; - -	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 response_payload run(device::Device &dev, -			const command_payload &payload) { -		using namespace device; - -		CommError status; -		OutgoingPacket outp; -		ResponsePacket resp; - -		// POD types can't have non-default constructors -		outp.initialize(); -		resp.initialize(); - -		outp.payload = payload; -		outp.update_CRC(); - -		if (!outp.isValid()) -			throw std::runtime_error("Invalid outgoing packet"); - -		status = dev.send(&outp); -		if ((int)(status) < 0 && status != CommError::ERR_NO_ERROR)  -			throw std::runtime_error( -				std::string("Device error while sending command ") + -				std::to_string((int)(status))); - -		status = dev.recv(&resp); -		if ((int)(status) < 0 && status != CommError::ERR_NO_ERROR)  -			throw std::runtime_error( -				std::string("Device error while executing command ") + -				std::to_string((int)(status))); - -		if (!resp.isValid()) -			throw std::runtime_error("Invalid incoming packet"); - -		// See: DeviceResponse -		return resp.payload; -	} - -	static response_payload run(device::Device &dev) { -		command_payload empty_payload; -		return run(dev, empty_payload); -	} + 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; + +  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; +  } + +  static response_payload run(device::Device &dev, +                              const command_payload &payload) { +    using namespace ::nitrokey::device; +    using namespace ::nitrokey::log; + +    Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2); + +    CommError status; +    OutgoingPacket outp; +    ResponsePacket resp; + +    // POD types can't have non-default constructors +    outp.initialize(); +    resp.initialize(); + +    outp.payload = payload; +    outp.update_CRC(); + +    Log::instance()("Outgoing HID packet:", Loglevel::DEBUG); +    Log::instance()((std::string)(outp), Loglevel::DEBUG); + +    if (!outp.isValid()) throw std::runtime_error("Invalid outgoing packet"); + +    status = dev.send(&outp); +    if ((int)(status) < 0 && status != CommError::ERR_NO_ERROR) +      throw std::runtime_error( +          std::string("Device error while sending command ") + +          std::to_string((int)(status))); + +    // FIXME make checks done in device:recv here +    int retry = dev.get_retry_count(); +    while (retry-- > 0) { +      status = dev.recv(&resp); +      if (resp.device_status == 0) break; +      Log::instance()("Device status is not ready (CRC error?) retrying..", +                      Loglevel::DEBUG);  // FIXME translate device_status to log +      Log::instance()("Invalid incoming HID packet:", Loglevel::DEBUG_L2); +      Log::instance()((std::string)(resp), Loglevel::DEBUG_L2); +      std::this_thread::sleep_for(dev.get_retry_timeout()); +      continue; +    } +    if ((int)(status) < 0 && status != CommError::ERR_NO_ERROR) +      throw std::runtime_error( +          std::string("Device error while executing command ") + +          std::to_string((int)(status))); + +    Log::instance()("Incoming HID packet:", Loglevel::DEBUG); +    Log::instance()((std::string)(resp), Loglevel::DEBUG); + +    if (!resp.isValid()) throw std::runtime_error("Invalid incoming packet"); + +    // See: DeviceResponse +    return resp.payload; +  } + +  static response_payload run(device::Device &dev) { +    command_payload empty_payload; +    return run(dev, empty_payload); +  }  }; - -/* - *	Stick10 protocol definition - */ -namespace stick10 { -	namespace command { -		class GetSlotName : semantics::non_constructible { -		public: -			// reachable as a typedef in Transaction -			struct CommandPayload { -				uint8_t slot_number; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			struct ResponsePayload { -				uint8_t slot_name[15]; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::READ_SLOT_NAME, -								struct CommandPayload, -								struct ResponsePayload> CommandTransaction; -		}; - -		class EraseSlot : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t slot_number; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			typedef Transaction<CommandID::ERASE_SLOT, -								struct CommandPayload, -								struct EmptyPayload> CommandTransaction; -		}; - -		class SetTime : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t		reset; // 0 - get time, 1 - set time -				uint64_t	time; // posix time - -				bool isValid() const { -					return reset && reset != 1; -				} -			} __packed; - -			typedef Transaction<CommandID::SET_TIME, -								struct CommandPayload, -								struct EmptyPayload> CommandTransaction; -		}; - -		// TODO duplicate TOTP -		class WriteToHOTPSlot : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t slot_number; -				uint8_t slot_name[15]; -				uint8_t slot_secret[20]; -				uint8_t slot_config; -				uint8_t slot_token_id[13]; -				uint8_t slot_counter[8]; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			typedef Transaction<CommandID::WRITE_TO_SLOT, -							struct CommandPayload, -							struct EmptyPayload> CommandTransaction; -		}; - -		class WriteToTOTPSlot : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t slot_number; -				uint8_t slot_name[15]; -				uint8_t slot_secret[20]; -				uint8_t slot_config; -				uint8_t slot_token_id[13]; -				uint16_t slot_interval; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			typedef Transaction<CommandID::WRITE_TO_SLOT, -								struct CommandPayload, -								struct EmptyPayload> CommandTransaction; -		}; - -		class GetCode : semantics::non_constructible { -		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); -				} -			} __packed; - -			struct ResponsePayload { -				uint8_t code[18]; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::GET_CODE, -								struct CommandPayload, -								struct ResponsePayload> CommandTransaction; -		}; - -		class GetHOTP : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t slot_number; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			typedef Transaction<CommandID::GET_CODE, -								struct CommandPayload, -								struct EmptyPayload> CommandTransaction; -		}; - -		class ReadSlot : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t slot_number; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			struct ResponsePayload { -				uint8_t slot_name[15]; -				uint8_t config; -				uint8_t token_id[13]; -				uint64_t counter; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::READ_SLOT, -								struct CommandPayload, -								struct ResponsePayload> CommandTransaction; -		}; - -		class GetStatus : semantics::non_constructible { -		public: -			struct ResponsePayload { -				uint16_t firmware_version; -				uint8_t	card_serial[4]; -				uint8_t	general_config[3]; -				uint8_t	otp_password_config[2]; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::GET_STATUS, -								struct EmptyPayload, -								struct ResponsePayload> CommandTransaction; -		}; - -		class GetPasswordRetryCount : semantics::non_constructible { -		public: -			struct ResponsePayload { -				uint8_t password_retry_count; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::GET_PASSWORD_RETRY_COUNT, -								struct EmptyPayload, -								struct ResponsePayload> CommandTransaction; -		}; - -		class GetUserPasswordRetryCount : semantics::non_constructible { -		public: -			struct ResponsePayload { -				uint8_t password_retry_count; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::GET_USER_PASSWORD_RETRY_COUNT, -								struct EmptyPayload, -								struct ResponsePayload> CommandTransaction; -		}; - -		class GetPasswordSafeSlotStatus : semantics::non_constructible { -		public: -			struct ResponsePayload { -				uint8_t password_safe_status[PWS_SLOT_COUNT]; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::GET_PW_SAFE_SLOT_STATUS, -								struct EmptyPayload, -								struct ResponsePayload> CommandTransaction; -		}; - -		class GetPasswordSafeSlotName : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t slot_number; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			struct ResponsePayload { -				uint8_t slot_name[PWS_SLOTNAME_LENGTH]; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::GET_PW_SAFE_SLOT_NAME, -								struct CommandPayload, -								struct ResponsePayload> CommandTransaction; -		}; - -		class GetPasswordSafeSlotPassword : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t slot_number; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			struct ResponsePayload { -				uint8_t slot_password[PWS_PASSWORD_LENGTH]; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::GET_PW_SAFE_SLOT_PASSWORD, -								struct CommandPayload, -								struct ResponsePayload> CommandTransaction; -		}; - -		class GetPasswordSafeSlotLogin : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t slot_number; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			struct ResponsePayload { -				uint8_t slot_login[PWS_LOGINNAME_LENGTH]; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::GET_PW_SAFE_SLOT_LOGINNAME, -								struct CommandPayload, -								struct ResponsePayload> CommandTransaction; -		}; - -		class SetPasswordSafeSlotData : semantics::non_constructible { -		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); -				} -			} __packed; - -			typedef Transaction<CommandID::SET_PW_SAFE_SLOT_DATA_1, -								struct CommandPayload, -								struct EmptyPayload> CommandTransaction; -		}; - -		class SetPasswordSafeSlotData2 : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t slot_number; -				uint8_t slot_name[PWS_SLOTNAME_LENGTH]; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			typedef Transaction<CommandID::SET_PW_SAFE_SLOT_DATA_2, -								struct CommandPayload, -								struct EmptyPayload> CommandTransaction; -		}; - -		class ErasePasswordSafeSlot : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t slot_number; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			typedef Transaction<CommandID::PW_SAFE_ERASE_SLOT, -								struct CommandPayload, -								struct EmptyPayload> CommandTransaction; -		}; - -		class EnablePasswordSafe : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::PW_SAFE_ENABLE, -								struct CommandPayload, -								struct EmptyPayload> CommandTransaction; -		}; - -		class PasswordSafeInitKey : semantics::non_constructible { -		public: -			typedef Transaction<CommandID::PW_SAFE_INIT_KEY, -								struct EmptyPayload, -								struct EmptyPayload> CommandTransaction; -		}; - -		// TODO naming screwed up, see above -		class PasswordSafeSendSlotViaHID: semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t slot_number; -				uint8_t slot_kind; - -				bool isValid() const { -					return !(slot_number & 0xF0); -				} -			} __packed; - -			typedef Transaction<CommandID::PW_SAFE_SEND_DATA, -								struct CommandPayload, -								struct EmptyPayload> CommandTransaction; -		}; - - -		// TODO "Device::passwordSafeSendSlotDataViaHID" - -		class WriteGeneralConfig : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t	config[5]; -			} __packed; - -			typedef Transaction<CommandID::WRITE_CONFIG, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class FirstAuthenticate : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t card_password[25]; -				uint8_t temporary_password[25]; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::FIRST_AUTHENTICATE, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class UserAuthenticate : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t card_password[25]; -				uint8_t temporary_password[25]; - -				bool isValid() const { -					return true; -				} -			} __packed; - -			typedef Transaction<CommandID::USER_AUTHENTICATE, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class Authorize : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t crc[4]; -				uint8_t password[25]; -			} __packed; - -			typedef Transaction<CommandID::AUTHORIZE, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class UserAuthorize : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t crc[4]; -				uint8_t password[25]; -			} __packed; - -			typedef Transaction<CommandID::USER_AUTHORIZE, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class UnlockUserPassword : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t admin_password[20]; // TODO -			} __packed; - -			// TODO could we get the stick to return the retry count? - -			typedef Transaction<CommandID::UNLOCK_USER_PASSWORD, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class ChangeUserPin : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t old_pin[25]; -				uint8_t new_pin[25]; -			} __packed; - -			typedef Transaction<CommandID::CHANGE_USER_PIN, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		// TODO why is it needed? -		class IsAESSupported : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[20]; -			} __packed; - -			typedef Transaction<CommandID::DETECT_SC_AES, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class ChangeAdminPin : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t old_pin[25]; -				uint8_t new_pin[25]; -			} __packed; - -			typedef Transaction<CommandID::CHANGE_ADMIN_PIN, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class LockDevice : semantics::non_constructible { -		public: -			typedef Transaction<CommandID::LOCK_DEVICE, -									struct EmptyPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class FactoryReset : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[20]; -			} __packed; - -			typedef Transaction<CommandID::FACTORY_RESET, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class BuildAESKey : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[20]; -			} __packed; - -			typedef Transaction<CommandID::NEW_AES_KEY, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; -	} -} - -/* -*	STICK20 protocol command ids -*	a superset of STICK10 -*/ -namespace stick20 { -	namespace command { -		class EnableEncryptedPartition : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; // TODO check w/ firmware -			}; - -			typedef Transaction<CommandID::ENABLE_CRYPTED_PARI, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class DisableEncryptedPartition : semantics::non_constructible { -		public: -			typedef Transaction<CommandID::DISABLE_CRYPTED_PARI, -									struct EmptyPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class EnableHiddenEncryptedPartition : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; // TODO check w/ firmware -			}; - -			typedef Transaction<CommandID::ENABLE_HIDDEN_CRYPTED_PARI, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class DisableHiddenEncryptedPartition : semantics::non_constructible { -		public: -			typedef Transaction<CommandID::DISABLE_CRYPTED_PARI, -									struct EmptyPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class EnableFirmwareUpdate : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; // TODO check w/ firmware -			}; - -			typedef Transaction<CommandID::ENABLE_FIRMWARE_UPDATE, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class UpdatePassword : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t old_password[15]; -				uint8_t new_password[15]; -			}; - -			typedef Transaction<CommandID::CHANGE_UPDATE_PIN, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class ExportFirmware : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; -			}; - -			typedef Transaction<CommandID::EXPORT_FIRMWARE_TO_FILE, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class CreateNewKeys : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; -			}; - -			typedef Transaction<CommandID::GENERATE_NEW_KEYS, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class FillSDCardWithRandomChars : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t volume_flag; -				uint8_t password[30]; -			}; - -			typedef Transaction<CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class SetupHiddenVolume : semantics::non_constructible { -		public: -			typedef Transaction<CommandID::SEND_HIDDEN_VOLUME_SETUP, -									struct EmptyPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class SendPasswordMatrix : semantics::non_constructible { -		public: -			typedef Transaction<CommandID::SEND_PASSWORD_MATRIX, -									struct EmptyPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class SendPasswordMatrixPinData : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t pin_data[30]; // TODO how long actually can it be? -			}; - -			typedef Transaction<CommandID::SEND_PASSWORD_MATRIX_PINDATA, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class SendPasswordMatrixSetup : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t setup_data[30]; // TODO how long actually can it be? -			}; - -			typedef Transaction<CommandID::SEND_PASSWORD_MATRIX_SETUP, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class GetDeviceStatus : semantics::non_constructible { -		public: -			typedef Transaction<CommandID::GET_DEVICE_STATUS, -									struct EmptyPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class SendPassword : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; -			}; - -			typedef Transaction<CommandID::SEND_PASSWORD, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class SendNewPassword : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; -			}; - -			typedef Transaction<CommandID::SEND_NEW_PASSWORD, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		// TODO fix original nomenclature -		class SendSetReadonlyToUncryptedVolume : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; -			}; - -			typedef Transaction<CommandID::ENABLE_READWRITE_UNCRYPTED_LUN, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class SendSetReadwriteToUncryptedVolume : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; -			}; - -			typedef Transaction<CommandID::ENABLE_READWRITE_UNCRYPTED_LUN, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class SendClearNewSdCardFound : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; -			}; - -			typedef Transaction<CommandID::CLEAR_NEW_SD_CARD_FOUND, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class SendStartup : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint64_t localtime; // POSIX -			}; - -			typedef Transaction<CommandID::SEND_STARTUP, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class SendHiddenVolumeSetup : semantics::non_constructible { -		public: -			struct CommandPayload { -				// TODO HiddenVolumeSetup_tst type -			}; - -			typedef Transaction<CommandID::SEND_HIDDEN_VOLUME_SETUP, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class LockFirmware : semantics::non_constructible { -		public: -			struct CommandPayload { -				uint8_t password[30]; -			}; - -			typedef Transaction<CommandID::SEND_LOCK_STICK_HARDWARE, -									struct CommandPayload, -									struct EmptyPayload> CommandTransaction; -		}; - -		class ProductionTest : semantics::non_constructible { -		public: -			typedef Transaction<CommandID::PRODUCTION_TEST, -									struct EmptyPayload, -									struct EmptyPayload> CommandTransaction; -		}; -	}  }  } -  #endif diff --git a/include/dissect.h b/include/dissect.h new file mode 100644 index 0000000..993d348 --- /dev/null +++ b/include/dissect.h @@ -0,0 +1,82 @@ +/* + *	Protocol packet dissection + */ +#ifndef DISSECT_H +#define DISSECT_H +#include <string> +#include <sstream> +#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; + +    out << "Raw HID packet:" << std::endl; +    out << ::nitrokey::misc::hexdump((const char *)(&pod), sizeof pod); + +    out << "Contents:" << std::endl; +    out << "Command ID:\t" << commandid_to_string((CommandID)(pod.command_id)) +        << std::endl; +    out << "CRC:\t" << 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 dissect(const HIDPacket &pod) { +    std::stringstream out; + +    // FIXME use values from firmware (possibly generate separate +    // header automatically) +    std::string status[4]; +    status[0] = " STATUS_READY"; +    status[1] = " STATUS_BUSY"; +    status[2] = " STATUS_ERROR"; +    status[3] = " STATUS_RECEIVED_REPORT"; +    std::string cmd[11]; +    cmd[0] = " CMD_STATUS_OK"; +    cmd[1] = " CMD_STATUS_WRONG_CRC"; +    cmd[2] = " CMD_STATUS_WRONG_SLOT"; +    cmd[3] = " CMD_STATUS_SLOT_NOT_PROGRAMMED"; +    cmd[4] = " CMD_STATUS_WRONG_PASSWORD"; +    cmd[5] = " CMD_STATUS_NOT_AUTHORIZED"; +    cmd[6] = " CMD_STATUS_TIMESTAMP_WARNING"; +    cmd[7] = " CMD_STATUS_NO_NAME_ERROR"; +    cmd[8] = " CMD_STATUS_NOT_SUPPORTED"; +    cmd[9] = " CMD_STATUS_UNKNOWN_COMMAND"; +    cmd[10] = " CMD_STATUS_AES_DEC_FAILED"; + +    out << "Raw HID packet:" << std::endl; +    out << ::nitrokey::misc::hexdump((const char *)(&pod), sizeof pod); + +    out << "Device status:\t" << pod.device_status + 0 << " " +        << status[pod.device_status] << std::endl; +    out << "Command ID:\t" << commandid_to_string((CommandID)(pod.command_id)) +        << std::endl; +    out << "Last command CRC:\t" << pod.last_command_crc << std::endl; +    out << "Last command status:\t" << pod.last_command_status + 0 << " " +        << cmd[pod.last_command_status] << std::endl; +    out << "CRC:\t" << pod.crc << std::endl; + +    out << "Payload:" << std::endl; +    out << pod.payload.dissect(); +    return out.str(); +  } +}; +} +} + +#endif diff --git a/include/inttypes.h b/include/inttypes.h new file mode 100644 index 0000000..de2cc83 --- /dev/null +++ b/include/inttypes.h @@ -0,0 +1,522 @@ +/* Copyright (c) 2004,2005,2007 Joerg Wunsch Copyright (c) 2005, Carlos Lamas All rights reserved. + +   Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +   * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +   * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the +   documentation and/or other materials provided with the distribution. + +   * Neither the name of the copyright holders nor the names of contributors may be used to endorse or promote products derived from this software +   without specific prior written permission. + +   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +   EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* $Id: inttypes.h 1766 2008-10-17 21:33:57Z arcanum $ */ + +#ifndef __INTTYPES_H_ +#define __INTTYPES_H_ + +#include <stdint.h> + +/** \file */ +/** \defgroup avr_inttypes <inttypes.h>: Integer Type conversions +    \code #include <inttypes.h> \endcode + +    This header file includes the exact-width integer definitions from +    <tt><stdint.h></tt>, and extends them with additional facilities +    provided by the implementation. + +    Currently, the extensions include two additional integer types +    that could hold a "far" pointer (i.e. a code pointer that can +    address more than 64 KB), as well as standard names for all printf +    and scanf formatting options that are supported by the \ref avr_stdio. +    As the library does not support the full range of conversion +    specifiers from ISO 9899:1999, only those conversions that are +    actually implemented will be listed here. + +    The idea behind these conversion macros is that, for each of the +    types defined by <stdint.h>, a macro will be supplied that portably +    allows formatting an object of that type in printf() or scanf() +    operations.  Example: + +    \code +    #include <inttypes.h> + +    uint8_t smallval; +    int32_t longval; +    ... +    printf("The hexadecimal value of smallval is %" PRIx8 +           ", the decimal value of longval is %" PRId32 ".\n", +	   smallval, longval); +    \endcode +*/ + +/** \name Far pointers for memory access >64K */ + +/* @{ */ +/** \ingroup avr_inttypes +    signed integer type that can hold a pointer > 64 KB */ +typedef int32_t int_farptr_t; + +/** \ingroup avr_inttypes +    unsigned integer type that can hold a pointer > 64 KB */ +typedef uint32_t uint_farptr_t; + +/* @} */ + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) + + +/** \name macros for printf and scanf format specifiers + +    For C++, these are only included if __STDC_LIMIT_MACROS +    is defined before including <inttypes.h>. + */ + +/* @{ */ +/** \ingroup avr_inttypes +    decimal printf format for int8_t */ +#define		PRId8			"d" +/** \ingroup avr_inttypes +    decimal printf format for int_least8_t */ +#define		PRIdLEAST8		"d" +/** \ingroup avr_inttypes +    decimal printf format for int_fast8_t */ +#define		PRIdFAST8		"d" + +/** \ingroup avr_inttypes +    integer printf format for int8_t */ +#define		PRIi8			"i" +/** \ingroup avr_inttypes +    integer printf format for int_least8_t */ +#define		PRIiLEAST8		"i" +/** \ingroup avr_inttypes +    integer printf format for int_fast8_t */ +#define		PRIiFAST8		"i" + + +/** \ingroup avr_inttypes +    decimal printf format for int16_t */ +#define		PRId16			"d" +/** \ingroup avr_inttypes +    decimal printf format for int_least16_t */ +#define		PRIdLEAST16		"d" +/** \ingroup avr_inttypes +    decimal printf format for int_fast16_t */ +#define		PRIdFAST16		"d" + +/** \ingroup avr_inttypes +    integer printf format for int16_t */ +#define		PRIi16			"i" +/** \ingroup avr_inttypes +    integer printf format for int_least16_t */ +#define		PRIiLEAST16		"i" +/** \ingroup avr_inttypes +    integer printf format for int_fast16_t */ +#define		PRIiFAST16		"i" + + +/** \ingroup avr_inttypes +    decimal printf format for int32_t */ +#define		PRId32			"ld" +/** \ingroup avr_inttypes +    decimal printf format for int_least32_t */ +#define		PRIdLEAST32		"ld" +/** \ingroup avr_inttypes +    decimal printf format for int_fast32_t */ +#define		PRIdFAST32		"ld" + +/** \ingroup avr_inttypes +    integer printf format for int32_t */ +#define		PRIi32			"li" +/** \ingroup avr_inttypes +    integer printf format for int_least32_t */ +#define		PRIiLEAST32		"li" +/** \ingroup avr_inttypes +    integer printf format for int_fast32_t */ +#define		PRIiFAST32		"li" + + +#ifdef __avr_libc_does_not_implement_long_long_in_printf_or_scanf + +#define		PRId64			"lld" +#define		PRIdLEAST64		"lld" +#define		PRIdFAST64		"lld" + +#define		PRIi64			"lli" +#define		PRIiLEAST64		"lli" +#define		PRIiFAST64		"lli" + + +#define		PRIdMAX			"lld" +#define		PRIiMAX			"lli" + +#endif + +/** \ingroup avr_inttypes +    decimal printf format for intptr_t */ +#define		PRIdPTR			PRId16 +/** \ingroup avr_inttypes +    integer printf format for intptr_t */ +#define		PRIiPTR			PRIi16 + +/** \ingroup avr_inttypes +    octal printf format for uint8_t */ +#define		PRIo8			"o" +/** \ingroup avr_inttypes +    octal printf format for uint_least8_t */ +#define		PRIoLEAST8		"o" +/** \ingroup avr_inttypes +    octal printf format for uint_fast8_t */ +#define		PRIoFAST8		"o" + +/** \ingroup avr_inttypes +    decimal printf format for uint8_t */ +#define		PRIu8			"u" +/** \ingroup avr_inttypes +    decimal printf format for uint_least8_t */ +#define		PRIuLEAST8		"u" +/** \ingroup avr_inttypes +    decimal printf format for uint_fast8_t */ +#define		PRIuFAST8		"u" + +/** \ingroup avr_inttypes +    hexadecimal printf format for uint8_t */ +#define		PRIx8			"x" +/** \ingroup avr_inttypes +    hexadecimal printf format for uint_least8_t */ +#define		PRIxLEAST8		"x" +/** \ingroup avr_inttypes +    hexadecimal printf format for uint_fast8_t */ +#define		PRIxFAST8		"x" + +/** \ingroup avr_inttypes +    uppercase hexadecimal printf format for uint8_t */ +#define		PRIX8			"X" +/** \ingroup avr_inttypes +    uppercase hexadecimal printf format for uint_least8_t */ +#define		PRIXLEAST8		"X" +/** \ingroup avr_inttypes +    uppercase hexadecimal printf format for uint_fast8_t */ +#define		PRIXFAST8		"X" + + +/** \ingroup avr_inttypes +    octal printf format for uint16_t */ +#define		PRIo16			"o" +/** \ingroup avr_inttypes +    octal printf format for uint_least16_t */ +#define		PRIoLEAST16		"o" +/** \ingroup avr_inttypes +    octal printf format for uint_fast16_t */ +#define		PRIoFAST16		"o" + +/** \ingroup avr_inttypes +    decimal printf format for uint16_t */ +#define		PRIu16			"u" +/** \ingroup avr_inttypes +    decimal printf format for uint_least16_t */ +#define		PRIuLEAST16		"u" +/** \ingroup avr_inttypes +    decimal printf format for uint_fast16_t */ +#define		PRIuFAST16		"u" + +/** \ingroup avr_inttypes +    hexadecimal printf format for uint16_t */ +#define		PRIx16			"x" +/** \ingroup avr_inttypes +    hexadecimal printf format for uint_least16_t */ +#define		PRIxLEAST16		"x" +/** \ingroup avr_inttypes +    hexadecimal printf format for uint_fast16_t */ +#define		PRIxFAST16		"x" + +/** \ingroup avr_inttypes +    uppercase hexadecimal printf format for uint16_t */ +#define		PRIX16			"X" +/** \ingroup avr_inttypes +    uppercase hexadecimal printf format for uint_least16_t */ +#define		PRIXLEAST16		"X" +/** \ingroup avr_inttypes +    uppercase hexadecimal printf format for uint_fast16_t */ +#define		PRIXFAST16		"X" + + +/** \ingroup avr_inttypes +    octal printf format for uint32_t */ +#define		PRIo32			"lo" +/** \ingroup avr_inttypes +    octal printf format for uint_least32_t */ +#define		PRIoLEAST32		"lo" +/** \ingroup avr_inttypes +    octal printf format for uint_fast32_t */ +#define		PRIoFAST32		"lo" + +/** \ingroup avr_inttypes +    decimal printf format for uint32_t */ +#define		PRIu32			"lu" +/** \ingroup avr_inttypes +    decimal printf format for uint_least32_t */ +#define		PRIuLEAST32		"lu" +/** \ingroup avr_inttypes +    decimal printf format for uint_fast32_t */ +#define		PRIuFAST32		"lu" + +/** \ingroup avr_inttypes +    hexadecimal printf format for uint32_t */ +#define		PRIx32			"lx" +/** \ingroup avr_inttypes +    hexadecimal printf format for uint_least32_t */ +#define		PRIxLEAST32		"lx" +/** \ingroup avr_inttypes +    hexadecimal printf format for uint_fast32_t */ +#define		PRIxFAST32		"lx" + +/** \ingroup avr_inttypes +    uppercase hexadecimal printf format for uint32_t */ +#define		PRIX32			"lX" +/** \ingroup avr_inttypes +    uppercase hexadecimal printf format for uint_least32_t */ +#define		PRIXLEAST32		"lX" +/** \ingroup avr_inttypes +    uppercase hexadecimal printf format for uint_fast32_t */ +#define		PRIXFAST32		"lX" + + +#ifdef __avr_libc_does_not_implement_long_long_in_printf_or_scanf + +#define		PRIo64			"llo" +#define		PRIoLEAST64		"llo" +#define		PRIoFAST64		"llo" + +#define		PRIu64			"llu" +#define		PRIuLEAST64		"llu" +#define		PRIuFAST64		"llu" + +#define		PRIx64			"llx" +#define		PRIxLEAST64		"llx" +#define		PRIxFAST64		"llx" + +#define		PRIX64			"llX" +#define		PRIXLEAST64		"llX" +#define		PRIXFAST64		"llX" + +#define		PRIoMAX			"llo" +#define		PRIuMAX			"llu" +#define		PRIxMAX			"llx" +#define		PRIXMAX			"llX" + +#endif + +/** \ingroup avr_inttypes +    octal printf format for uintptr_t */ +#define		PRIoPTR			PRIo16 +/** \ingroup avr_inttypes +    decimal printf format for uintptr_t */ +#define		PRIuPTR			PRIu16 +/** \ingroup avr_inttypes +    hexadecimal printf format for uintptr_t */ +#define		PRIxPTR			PRIx16 +/** \ingroup avr_inttypes +    uppercase hexadecimal printf format for uintptr_t */ +#define		PRIXPTR			PRIX16 + + +#ifdef __avr_libc_does_not_implement_hh_in_scanf + +#define		SCNd8			"hhd" +#define		SCNdLEAST8		"hhd" +#define		SCNdFAST8		"hhd" + +#define		SCNi8			"hhi" +#define		SCNiLEAST8		"hhi" +#define		SCNiFAST8		"hhi" + +#endif + + +/** \ingroup avr_inttypes +    decimal scanf format for int16_t */ +#define		SCNd16			"d" +/** \ingroup avr_inttypes +    decimal scanf format for int_least16_t */ +#define		SCNdLEAST16		"d" +/** \ingroup avr_inttypes +    decimal scanf format for int_fast16_t */ +#define		SCNdFAST16		"d" + +/** \ingroup avr_inttypes +    generic-integer scanf format for int16_t */ +#define		SCNi16			"i" +/** \ingroup avr_inttypes +    generic-integer scanf format for int_least16_t */ +#define		SCNiLEAST16		"i" +/** \ingroup avr_inttypes +    generic-integer scanf format for int_fast16_t */ +#define		SCNiFAST16		"i" + + +/** \ingroup avr_inttypes +    decimal scanf format for int32_t */ +#define		SCNd32			"ld" +/** \ingroup avr_inttypes +    decimal scanf format for int_least32_t */ +#define		SCNdLEAST32		"ld" +/** \ingroup avr_inttypes +    decimal scanf format for int_fast32_t */ +#define		SCNdFAST32		"ld" + +/** \ingroup avr_inttypes +    generic-integer scanf format for int32_t */ +#define		SCNi32			"li" +/** \ingroup avr_inttypes +    generic-integer scanf format for int_least32_t */ +#define		SCNiLEAST32		"li" +/** \ingroup avr_inttypes +    generic-integer scanf format for int_fast32_t */ +#define		SCNiFAST32		"li" + + +#ifdef __avr_libc_does_not_implement_long_long_in_printf_or_scanf + +#define		SCNd64			"lld" +#define		SCNdLEAST64		"lld" +#define		SCNdFAST64		"lld" + +#define		SCNi64			"lli" +#define		SCNiLEAST64		"lli" +#define		SCNiFAST64		"lli" + +#define		SCNdMAX			"lld" +#define		SCNiMAX			"lli" + +#endif + +/** \ingroup avr_inttypes +    decimal scanf format for intptr_t */ +#define		SCNdPTR			SCNd16 +/** \ingroup avr_inttypes +    generic-integer scanf format for intptr_t */ +#define		SCNiPTR			SCNi16 + +#ifdef __avr_libc_does_not_implement_hh_in_scanf + +#define		SCNo8			"hho" +#define		SCNoLEAST8		"hho" +#define		SCNoFAST8		"hho" + +#define		SCNu8			"hhu" +#define		SCNuLEAST8		"hhu" +#define		SCNuFAST8		"hhu" + +#define		SCNx8			"hhx" +#define		SCNxLEAST8		"hhx" +#define		SCNxFAST8		"hhx" + +#endif + +/** \ingroup avr_inttypes +    octal scanf format for uint16_t */ +#define		SCNo16			"o" +/** \ingroup avr_inttypes +    octal scanf format for uint_least16_t */ +#define		SCNoLEAST16		"o" +/** \ingroup avr_inttypes +    octal scanf format for uint_fast16_t */ +#define		SCNoFAST16		"o" + +/** \ingroup avr_inttypes +    decimal scanf format for uint16_t */ +#define		SCNu16			"u" +/** \ingroup avr_inttypes +    decimal scanf format for uint_least16_t */ +#define		SCNuLEAST16		"u" +/** \ingroup avr_inttypes +    decimal scanf format for uint_fast16_t */ +#define		SCNuFAST16		"u" + +/** \ingroup avr_inttypes +    hexadecimal scanf format for uint16_t */ +#define		SCNx16			"x" +/** \ingroup avr_inttypes +    hexadecimal scanf format for uint_least16_t */ +#define		SCNxLEAST16		"x" +/** \ingroup avr_inttypes +    hexadecimal scanf format for uint_fast16_t */ +#define		SCNxFAST16		"x" + + +/** \ingroup avr_inttypes +    octal scanf format for uint32_t */ +#define		SCNo32			"lo" +/** \ingroup avr_inttypes +    octal scanf format for uint_least32_t */ +#define		SCNoLEAST32		"lo" +/** \ingroup avr_inttypes +    octal scanf format for uint_fast32_t */ +#define		SCNoFAST32		"lo" + +/** \ingroup avr_inttypes +    decimal scanf format for uint32_t */ +#define		SCNu32			"lu" +/** \ingroup avr_inttypes +    decimal scanf format for uint_least32_t */ +#define		SCNuLEAST32		"lu" +/** \ingroup avr_inttypes +    decimal scanf format for uint_fast32_t */ +#define		SCNuFAST32		"lu" + +/** \ingroup avr_inttypes +    hexadecimal scanf format for uint32_t */ +#define		SCNx32			"lx" +/** \ingroup avr_inttypes +    hexadecimal scanf format for uint_least32_t */ +#define		SCNxLEAST32		"lx" +/** \ingroup avr_inttypes +    hexadecimal scanf format for uint_fast32_t */ +#define		SCNxFAST32		"lx" + + +#ifdef __avr_libc_does_not_implement_long_long_in_printf_or_scanf + +#define		SCNo64			"llo" +#define		SCNoLEAST64		"llo" +#define		SCNoFAST64		"llo" + +#define		SCNu64			"llu" +#define		SCNuLEAST64		"llu" +#define		SCNuFAST64		"llu" + +#define		SCNx64			"llx" +#define		SCNxLEAST64		"llx" +#define		SCNxFAST64		"llx" + +#define		SCNoMAX			"llo" +#define		SCNuMAX			"llu" +#define		SCNxMAX			"llx" + +#endif + +/** \ingroup avr_inttypes +    octal scanf format for uintptr_t */ +#define		SCNoPTR			SCNo16 +/** \ingroup avr_inttypes +    decimal scanf format for uintptr_t */ +#define		SCNuPTR			SCNu16 +/** \ingroup avr_inttypes +    hexadecimal scanf format for uintptr_t */ +#define		SCNxPTR			SCNx16 + +/* @} */ + + +#endif /* !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) */ + + +#endif /* __INTTYPES_H_ */ diff --git a/include/log.h b/include/log.h new file mode 100644 index 0000000..8eda4fb --- /dev/null +++ b/include/log.h @@ -0,0 +1,50 @@ +#ifndef LOG_H +#define LOG_H +#include <string> +#include <cstddef> + +namespace nitrokey { +namespace log { + +enum class Loglevel : int { DEBUG_L2, DEBUG, INFO, WARNING, ERROR }; + +class LogHandler { + public: +  virtual void print(const std::string &, Loglevel lvl) = 0; + + protected: +  std::string loglevel_to_str(Loglevel); +}; + +class StdlogHandler : public LogHandler { + public: +  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 == NULL) 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: +  Loglevel m_loglevel; +  LogHandler *mp_loghandler; + +  static Log *mp_instance; +}; +} +} + +#endif diff --git a/include/misc.h b/include/misc.h new file mode 100644 index 0000000..07f221c --- /dev/null +++ b/include/misc.h @@ -0,0 +1,14 @@ +#ifndef MISC_H +#define MISC_H +#include <stdio.h> +#include <string> + +namespace nitrokey { +namespace misc { + +std::string hexdump(const char *p, size_t size); +uint32_t stm_crc32(const uint8_t *data, size_t size); +} +} + +#endif diff --git a/include/stick10_commands.h b/include/stick10_commands.h new file mode 100644 index 0000000..f1903aa --- /dev/null +++ b/include/stick10_commands.h @@ -0,0 +1,588 @@ +#ifndef STICK10_COMMANDS_H +#define STICK10_COMMANDS_H +#include <string> +#include <sstream> +#include "inttypes.h" +#include "command.h" + +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 & 0xF0); } +  } __packed; + +  struct ResponsePayload { +    uint8_t slot_name[15]; + +    bool isValid() const { return true; } +  } __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); } +  } __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; } +  } __packed; + +  typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> +      CommandTransaction; +}; + +// TODO duplicate TOTP +class WriteToHOTPSlot : Command<CommandID::WRITE_TO_SLOT> { + public: +  struct CommandPayload { +    uint8_t slot_number; +    uint8_t slot_name[15]; +    uint8_t slot_secret[20]; +    uint8_t slot_config; +    uint8_t slot_token_id[13]; +    uint8_t slot_counter[8]; + +    bool isValid() const { return !(slot_number & 0xF0); } +    std::string dissect() const { +        std::stringstream ss; +        ss << "slot_number:\t" << (int)(slot_number) << std::endl; +        ss << "slot_name:\t" << slot_name << std::endl; +        ss << "slot_secret:\t" << slot_secret << std::endl; +        ss << "slot_config:\t" << slot_config << std::endl; +        ss << "slot_token_id:\t" << slot_token_id << std::endl; +        ss << "slot_counter:\t" << slot_counter << std::endl; +        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]; +    uint8_t slot_config; +    uint8_t slot_token_id[13]; +    uint16_t slot_interval; + +    bool isValid() const { return !(slot_number & 0xF0); } +  } __packed; + +  typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> +      CommandTransaction; +}; + +class GetCode : 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); } +  } __packed; + +  struct ResponsePayload { +    uint8_t code[18]; + +    bool isValid() const { return true; } +  } __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]; //TODO remove if not needed +          struct { +              uint32_t code; +              uint8_t config; +          } __packed; +      } __packed; + +    bool isValid() const { return true; } +    std::string dissect() const { +      std::stringstream ss; +      ss << "code:\t" << (code) << std::endl; +      ss << "config:\t" << "TODO" /*(config) */<< std::endl; //TODO show byte field options +      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]; +    uint8_t config; +    uint8_t token_id[13]; +    uint64_t counter; + +    bool isValid() const { return true; } + +    std::string dissect() const { +      std::stringstream ss; +      ss << "slot_name:\t" << slot_name << std::endl; +      ss << "config:\t" << config << std::endl; +      ss << "token_id:\t" << token_id << std::endl; +      ss << "counter:\t" << counter << std::endl; +      return ss.str(); +    } +  } __packed; + +  typedef Transaction<command_id(), struct CommandPayload, +                      struct ResponsePayload> CommandTransaction; +}; + +class GetStatus : Command<CommandID::GET_STATUS> { + public: +  struct ResponsePayload { +    uint16_t firmware_version; +    uint8_t card_serial[4]; +    uint8_t general_config[3]; +    uint8_t otp_password_config[2]; + +    bool isValid() const { return true; } + +    std::string dissect() const { +      std::stringstream ss; +      ss << "firmware_version:\t" << firmware_version << std::endl; +      ss << "card_serial:\t" +         << ::nitrokey::misc::hexdump((const char *)(card_serial), +                                      sizeof card_serial); +      ss << "general_config:\t" +         << ::nitrokey::misc::hexdump((const char *)(general_config), +                                      sizeof general_config); +      ss << "otp_password_config:\t" +         << ::nitrokey::misc::hexdump((const char *)(otp_password_config), +                                      sizeof otp_password_config); +      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" << 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" << password_retry_count << std::endl; +      return ss.str(); +    } +  } __packed; + +  typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload> +      CommandTransaction; +}; + +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; } +  } __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" << 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; +      ss << " slot_name\t" << slot_name << std::endl; +      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" << 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; +      ss << " slot_password\t" << slot_password << std::endl; +      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" << 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; +      ss << " slot_login\t" << slot_login << std::endl; +      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); } +  } __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_name[PWS_SLOTNAME_LENGTH]; + +    bool isValid() const { return !(slot_number & 0xF0); } +  } __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); } +  } __packed; + +  typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> +      CommandTransaction; +}; + +class EnablePasswordSafe : Command<CommandID::PW_SAFE_ENABLE> { + public: +  struct CommandPayload { +    uint8_t password[30]; + +    bool isValid() const { return true; } +    std::string dissect() const { +      std::stringstream ss; +      ss << " password\t" << password << std::endl; +      return ss.str(); +    } +  } __packed; + +  typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> +      CommandTransaction; +}; + +class PasswordSafeInitKey : Command<CommandID::PW_SAFE_INIT_KEY> { + public: +  typedef Transaction<command_id(), struct EmptyPayload, struct EmptyPayload> +      CommandTransaction; +}; + +// TODO naming screwed up, see above +class PasswordSafeSendSlotViaHID : Command<CommandID::PW_SAFE_SEND_DATA> { + 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 { +    uint8_t config[5]; +  } __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; +      ss << "card_password:\t" << card_password << std::endl; +      ss << "temporary_password:\t" << temporary_password << std::endl; +      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; } +  } __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" <<   crc_to_authorize<< std::endl; +      ss << " temporary_password:\t" << temporary_password<< std::endl; +      return ss.str(); +    } +  } __packed; + +  typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> +      CommandTransaction; +}; + +class UserAuthorize : Command<CommandID::USER_AUTHORIZE> { + public: +  struct CommandPayload { +    uint8_t crc_to_authorize[4]; +    uint8_t temporary_password[25]; +    std::string dissect() const { +      std::stringstream ss; +      ss << " crc_to_authorize:\t" <<  crc_to_authorize<< std::endl; +      ss << " temporary_password:\t" << temporary_password<< std::endl; +      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[20];  // TODO +  } __packed; + +  // TODO could we get the stick to return the retry count? + +  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]; +  } __packed; + +  typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> +      CommandTransaction; +}; + +// TODO why is it needed? +class IsAESSupported : Command<CommandID::DETECT_SC_AES> { + public: +  struct CommandPayload { +    uint8_t password[20]; +  } __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]; +  } __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 password[20]; +  } __packed; + +  typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> +      CommandTransaction; +}; + +class BuildAESKey : Command<CommandID::NEW_AES_KEY> { + public: +  struct CommandPayload { +    uint8_t password[20]; +  } __packed; + +  typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> +      CommandTransaction; +}; +} +} +} +#endif diff --git a/include/stick20_commands.h b/include/stick20_commands.h new file mode 100644 index 0000000..b84d436 --- /dev/null +++ b/include/stick20_commands.h @@ -0,0 +1,233 @@ +#ifndef STICK20_COMMANDS_H +#define STICK20_COMMANDS_H +#include "inttypes.h" + +namespace nitrokey { +namespace proto { + +/* +*	STICK20 protocol command ids +*	a superset of STICK10 +*/ +namespace stick20 { +class EnableEncryptedPartition : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t password[30];  // TODO check w/ firmware +  }; + +  typedef Transaction<CommandID::ENABLE_CRYPTED_PARI, struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class DisableEncryptedPartition : semantics::non_constructible { + public: +  typedef Transaction<CommandID::DISABLE_CRYPTED_PARI, struct EmptyPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class EnableHiddenEncryptedPartition : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t password[30];  // TODO check w/ firmware +  }; + +  typedef Transaction<CommandID::ENABLE_HIDDEN_CRYPTED_PARI, +                      struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class DisableHiddenEncryptedPartition : semantics::non_constructible { + public: +  typedef Transaction<CommandID::DISABLE_CRYPTED_PARI, struct EmptyPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class EnableFirmwareUpdate : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t password[30];  // TODO check w/ firmware +  }; + +  typedef Transaction<CommandID::ENABLE_FIRMWARE_UPDATE, struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class UpdatePassword : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t old_password[15]; +    uint8_t new_password[15]; +  }; + +  typedef Transaction<CommandID::CHANGE_UPDATE_PIN, struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class ExportFirmware : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t password[30]; +  }; + +  typedef Transaction<CommandID::EXPORT_FIRMWARE_TO_FILE, struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class CreateNewKeys : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t password[30]; +  }; + +  typedef Transaction<CommandID::GENERATE_NEW_KEYS, struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class FillSDCardWithRandomChars : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t volume_flag; +    uint8_t password[30]; +  }; + +  typedef Transaction<CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS, +                      struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class SetupHiddenVolume : semantics::non_constructible { + public: +  typedef Transaction<CommandID::SEND_HIDDEN_VOLUME_SETUP, struct EmptyPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class SendPasswordMatrix : semantics::non_constructible { + public: +  typedef Transaction<CommandID::SEND_PASSWORD_MATRIX, struct EmptyPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class SendPasswordMatrixPinData : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t pin_data[30];  // TODO how long actually can it be? +  }; + +  typedef Transaction<CommandID::SEND_PASSWORD_MATRIX_PINDATA, +                      struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class SendPasswordMatrixSetup : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t setup_data[30];  // TODO how long actually can it be? +  }; + +  typedef Transaction<CommandID::SEND_PASSWORD_MATRIX_SETUP, +                      struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class GetDeviceStatus : semantics::non_constructible { + public: +  typedef Transaction<CommandID::GET_DEVICE_STATUS, struct EmptyPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class SendPassword : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t password[30]; +  }; + +  typedef Transaction<CommandID::SEND_PASSWORD, struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class SendNewPassword : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t password[30]; +  }; + +  typedef Transaction<CommandID::SEND_NEW_PASSWORD, struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +// TODO fix original nomenclature +class SendSetReadonlyToUncryptedVolume : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t password[30]; +  }; + +  typedef Transaction<CommandID::ENABLE_READWRITE_UNCRYPTED_LUN, +                      struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class SendSetReadwriteToUncryptedVolume : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t password[30]; +  }; + +  typedef Transaction<CommandID::ENABLE_READWRITE_UNCRYPTED_LUN, +                      struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class SendClearNewSdCardFound : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t password[30]; +  }; + +  typedef Transaction<CommandID::CLEAR_NEW_SD_CARD_FOUND, struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class SendStartup : semantics::non_constructible { + public: +  struct CommandPayload { +    uint64_t localtime;  // POSIX +  }; + +  typedef Transaction<CommandID::SEND_STARTUP, struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class SendHiddenVolumeSetup : semantics::non_constructible { + public: +  struct CommandPayload { +    // TODO HiddenVolumeSetup_tst type +  }; + +  typedef Transaction<CommandID::SEND_HIDDEN_VOLUME_SETUP, +                      struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class LockFirmware : semantics::non_constructible { + public: +  struct CommandPayload { +    uint8_t password[30]; +  }; + +  typedef Transaction<CommandID::SEND_LOCK_STICK_HARDWARE, +                      struct CommandPayload, +                      struct EmptyPayload> CommandTransaction; +}; + +class ProductionTest : semantics::non_constructible { + public: +  typedef Transaction<CommandID::PRODUCTION_TEST, struct EmptyPayload, +                      struct EmptyPayload> CommandTransaction; +}; +} +} +} + +#endif | 
