diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 33 | ||||
| -rw-r--r-- | command_id.cc | 147 | ||||
| -rw-r--r-- | crc32.cc | 37 | ||||
| -rw-r--r-- | device.cc | 19 | ||||
| -rw-r--r-- | include/command.h | 26 | ||||
| -rw-r--r-- | include/command_id.h | 86 | ||||
| -rw-r--r-- | include/crc32.h | 32 | ||||
| -rw-r--r-- | include/device.h | 4 | ||||
| -rw-r--r-- | include/device_proto.h | 917 | ||||
| -rw-r--r-- | include/dissect.h | 60 | ||||
| -rw-r--r-- | include/inttypes.h | 522 | ||||
| -rw-r--r-- | include/log.h | 63 | ||||
| -rw-r--r-- | include/misc.h | 15 | ||||
| -rw-r--r-- | include/stick10_commands.h | 582 | ||||
| -rw-r--r-- | include/stick20_commands.h | 249 | ||||
| -rw-r--r-- | log.cc | 44 | ||||
| -rw-r--r-- | misc.cc | 51 | ||||
| -rw-r--r-- | test.cc | 35 | ||||
| -rw-r--r-- | unittest/Makefile | 32 | ||||
| l--------- | unittest/build/libnitrokey.so | 1 | ||||
| -rw-r--r-- | unittest/test.cc | 34 | 
22 files changed, 1998 insertions, 992 deletions
| diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp @@ -6,26 +6,37 @@ INCLUDE = -Iinclude/  LIB = -lhidapi-libusb  BUILD = build -CXXFLAGS = -std=c++14 +CXXFLAGS = -std=c++14 -fPIC +SOFLAGS = -shared  CXXSOURCES = $(wildcard *.cc) -OBJ = $(CXXSOURCES:%.cc:$(BUILD)/%.o) +OBJ = $(CXXSOURCES:%.cc=$(BUILD)/%.o) +DEPENDS = $(CXXSOURCES:%.cc=$(BUILD)/%.d) -$(BUILD)/libnitrokey.so: $(OBJ) -	$(CXX) -shared $(OBJ) -o $@ +all: $(OBJ) $(BUILD)/libnitrokey.so unittest -$(BUILD)/%.o: %.cc -	$(CXX) -c $< -o $@ $(INCLUDE) $(CXXFLAGS) +$(BUILD)/libnitrokey.so: $(OBJ) $(DEPENDS) +	$(CXX) $(SOFLAGS) $(OBJ) -o $@ + +$(BUILD)/%.d: %.cc +	$(CXX) -M $< -o $@ $(INCLUDE) $(CXXFLAGS) -all: $(OBJ) $(BUILD)/libnitrokey.so +$(BUILD)/%.o: %.cc $(DEPENDS) +	$(CXX) -c $< -o $@ $(INCLUDE) $(CXXFLAGS)  clean: -	rm $(OBJ) -	rm $(BUILD)/libnitrokey.so +	rm -f $(OBJ) +	rm -f $(BUILD)/libnitrokey.so +	make -C unittest clean  mrproper: clean -	rm $(BUILD)/*.d +	rm -f $(BUILD)/*.d +	make -C unittest mrproper + +unittest: $(BUILD)/libnitrokey.so +	make -C unittest +	cd unittest/build && ln -fs ../../build/libnitrokey.so . -.PHONY: all clean mrproper +.PHONY: all clean mrproper unittest  include $(wildcard build/*.d) diff --git a/command_id.cc b/command_id.cc new file mode 100644 index 0000000..2c972c8 --- /dev/null +++ b/command_id.cc @@ -0,0 +1,147 @@ +#include <assert.h> +#include "command_id.h" + +namespace nitrokey { +namespace proto { + +const char * commandid_to_string(CommandID id) { +	switch (id) { +		case CommandID::GET_STATUS: +			return "GET_STATUS"; +		case CommandID::WRITE_TO_SLOT: +			return "WRITE_TO_SLOT"; +		case CommandID::READ_SLOT_NAME: +			return "READ_SLOT_NAME"; +		case CommandID::READ_SLOT: +			return "READ_SLOT"; +		case CommandID::GET_CODE: +			return "GET_CODE"; +		case CommandID::WRITE_CONFIG: +			return "WRITE_CONFIG"; +		case CommandID::ERASE_SLOT: +			return "ERASE_SLOT"; +		case CommandID::FIRST_AUTHENTICATE: +			return "FIRST_AUTHENTICATE"; +		case CommandID::AUTHORIZE: +			return "AUTHORIZE"; +		case CommandID::GET_PASSWORD_RETRY_COUNT: +			return "GET_PASSWORD_RETRY_COUNT"; +		case CommandID::CLEAR_WARNING: +			return "CLEAR_WARNING"; +		case CommandID::SET_TIME: +			return "SET_TIME"; +		case CommandID::TEST_COUNTER: +			return "TEST_COUNTER"; +		case CommandID::TEST_TIME: +			return "TEST_TIME"; +		case CommandID::USER_AUTHENTICATE: +			return "USER_AUTHENTICATE"; +		case CommandID::GET_USER_PASSWORD_RETRY_COUNT: +			return "GET_USER_PASSWORD_RETRY_COUNT"; +		case CommandID::USER_AUTHORIZE: +			return "USER_AUTHORIZE"; +		case CommandID::UNLOCK_USER_PASSWORD: +			return "UNLOCK_USER_PASSWORD"; +		case CommandID::LOCK_DEVICE: +			return "LOCK_DEVICE"; +		case CommandID::FACTORY_RESET: +			return "FACTORY_RESET"; +		case CommandID::CHANGE_USER_PIN: +			return "CHANGE_USER_PIN"; +		case CommandID::CHANGE_ADMIN_PIN: +			return "CHANGE_ADMIN_PIN"; + +		case CommandID::ENABLE_CRYPTED_PARI: +			return "ENABLE_CRYPTED_PARI"; +		case CommandID::DISABLE_CRYPTED_PARI: +			return "DISABLE_CRYPTED_PARI"; +		case CommandID::ENABLE_HIDDEN_CRYPTED_PARI: +			return "ENABLE_HIDDEN_CRYPTED_PARI"; +		case CommandID::DISABLE_HIDDEN_CRYPTED_PARI: +			return "DISABLE_HIDDEN_CRYPTED_PARI"; +		case CommandID::ENABLE_FIRMWARE_UPDATE: +			return "ENABLE_FIRMWARE_UPDATE"; +		case CommandID::EXPORT_FIRMWARE_TO_FILE: +			return "EXPORT_FIRMWARE_TO_FILE"; +		case CommandID::GENERATE_NEW_KEYS: +			return "GENERATE_NEW_KEYS"; +		case CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS: +			return "FILL_SD_CARD_WITH_RANDOM_CHARS"; + +		case CommandID::WRITE_STATUS_DATA: +			return "WRITE_STATUS_DATA"; +		case CommandID::ENABLE_READONLY_UNCRYPTED_LUN: +			return "ENABLE_READONLY_UNCRYPTED_LUN"; +		case CommandID::ENABLE_READWRITE_UNCRYPTED_LUN: +			return "ENABLE_READWRITE_UNCRYPTED_LUN"; + +		case CommandID::SEND_PASSWORD_MATRIX: +			return "SEND_PASSWORD_MATRIX"; +		case CommandID::SEND_PASSWORD_MATRIX_PINDATA: +			return "SEND_PASSWORD_MATRIX_PINDATA"; +		case CommandID::SEND_PASSWORD_MATRIX_SETUP: +			return "SEND_PASSWORD_MATRIX_SETUP"; + +		case CommandID::GET_DEVICE_STATUS: +			return "GET_DEVICE_STATUS"; +		case CommandID::SEND_DEVICE_STATUS: +			return "SEND_DEVICE_STATUS"; + +		case CommandID::SEND_HIDDEN_VOLUME_PASSWORD: +			return "SEND_HIDDEN_VOLUME_PASSWORD"; +		case CommandID::SEND_HIDDEN_VOLUME_SETUP: +			return "SEND_HIDDEN_VOLUME_SETUP"; +		case CommandID::SEND_PASSWORD: +			return "SEND_PASSWORD"; +		case CommandID::SEND_NEW_PASSWORD: +			return "SEND_NEW_PASSWORD"; +		case CommandID::CLEAR_NEW_SD_CARD_FOUND: +			return "CLEAR_NEW_SD_CARD_FOUND"; + +		case CommandID::SEND_STARTUP: +			return "SEND_STARTUP"; +		case CommandID::SEND_CLEAR_STICK_KEYS_NOT_INITIATED: +			return "SEND_CLEAR_STICK_KEYS_NOT_INITIATED"; +		case CommandID::SEND_LOCK_STICK_HARDWARE: +			return "SEND_LOCK_STICK_HARDWARE"; + +		case CommandID::PRODUCTION_TEST: +			return "PRODUCTION_TEST"; +		case CommandID::SEND_DEBUG_DATA: +			return "SEND_DEBUG_DATA"; + +		case CommandID::CHANGE_UPDATE_PIN: +			return "CHANGE_UPDATE_PIN"; + +		case CommandID::GET_PW_SAFE_SLOT_STATUS: +			return "GET_PW_SAFE_SLOT_STATUS"; +		case CommandID::GET_PW_SAFE_SLOT_NAME: +			return "GET_PW_SAFE_SLOT_NAME"; +		case CommandID::GET_PW_SAFE_SLOT_PASSWORD: +			return "GET_PW_SAFE_SLOT_PASSWORD"; +		case CommandID::GET_PW_SAFE_SLOT_LOGINNAME: +			return "GET_PW_SAFE_SLOT_LOGINNAME"; +		case CommandID::SET_PW_SAFE_SLOT_DATA_1: +			return "SET_PW_SAFE_SLOT_DATA_1"; +		case CommandID::SET_PW_SAFE_SLOT_DATA_2: +			return "SET_PW_SAFE_SLOT_DATA_2"; +		case CommandID::PW_SAFE_ERASE_SLOT: +			return "PW_SAFE_ERASE_SLOT"; +		case CommandID::PW_SAFE_ENABLE: +			return "PW_SAFE_ENABLE"; +		case CommandID::PW_SAFE_INIT_KEY: +			return "PW_SAFE_INIT_KEY"; +		case CommandID::PW_SAFE_SEND_DATA: +			return "PW_SAFE_SEND_DATA"; +		case CommandID::SD_CARD_HIGH_WATERMARK: +			return "SD_CARD_HIGH_WATERMARK"; +		case CommandID::DETECT_SC_AES: +			return "DETECT_SC_AES"; +		case CommandID::NEW_AES_KEY: +			return "NEW_AES_KEY"; +	} +	return "UNKNOWN"; +} + +} +} diff --git a/crc32.cc b/crc32.cc deleted file mode 100644 index 558d4ef..0000000 --- a/crc32.cc +++ /dev/null @@ -1,37 +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/>. - */ - -#include "crc32.h" - - -uint32_t Crc32 (uint32_t Crc, uint32_t Data) -{ -int i; - -    Crc = Crc ^ Data; - -    for (i = 0; i < 32; i++) -        if (Crc & 0x80000000) -            Crc = (Crc << 1) ^ 0x04C11DB7;  // Polynomial used in STM32 -        else -            Crc = (Crc << 1); - -    return (Crc); -} @@ -1,10 +1,14 @@  #include <chrono>  #include <thread>  #include <cstddef> +#include <stdexcept>  #include <hidapi/hidapi.h>  #include "device.h" +#include "log.h" +#include "misc.h" -using namespace device; +using namespace nitrokey::device; +using namespace nitrokey::log;  Device::Device()  : m_vid(0), m_pid(0), @@ -13,13 +17,19 @@ Device::Device()    mp_devhandle(NULL) {}  bool Device::connect() { -	hid_init(); +	Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2); +	hid_init();  	mp_devhandle = hid_open(m_vid, m_pid, NULL);  	return mp_devhandle != NULL;  }  CommError Device::send(const void *packet) { +	Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2); + +	if (mp_devhandle == NULL) +		throw std::runtime_error("Attempted HID send on an invalid descriptor."); +  	return (CommError)(  		hid_send_feature_report(mp_devhandle, (const unsigned char *)(packet),  			HID_REPORT_SIZE)); @@ -29,6 +39,11 @@ CommError Device::recv(void *packet) {  	CommError status;  	int retry_count = 0; +	Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2); + +	if (mp_devhandle == NULL) +		throw std::runtime_error("Attempted HID receive on an invalid descriptor."); +  	for(;;) {  		status = (CommError)(  			hid_get_feature_report(mp_devhandle, (unsigned char *)(packet), diff --git a/include/command.h b/include/command.h new file mode 100644 index 0000000..6a3e8b4 --- /dev/null +++ b/include/command.h @@ -0,0 +1,26 @@ +#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..124855b --- /dev/null +++ b/include/command_id.h @@ -0,0 +1,86 @@ +#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/device.h b/include/device.h index b2d83b5..dfc7149 100644 --- a/include/device.h +++ b/include/device.h @@ -8,7 +8,9 @@  // TODO !! SEMAPHORE +namespace nitrokey {  namespace device { +  enum class CommError   {  	ERR_NO_ERROR = 0, @@ -61,5 +63,7 @@ class Stick20 : public Device {  public:  	Stick20();  }; + +}  }  #endif diff --git a/include/device_proto.h b/include/device_proto.h index fb1dd4e..c8f1ff2 100644 --- a/include/device_proto.h +++ b/include/device_proto.h @@ -9,7 +9,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 @@ -25,94 +28,8 @@  #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; -} - +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. @@ -143,8 +60,8 @@ struct HIDReport {  	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)); +		return misc::stm_crc32((const uint8_t *)(this) + 1, +							(size_t)(HID_REPORT_SIZE - 5));  	}  	void update_CRC() { @@ -156,7 +73,14 @@ struct HIDReport {  	}  	bool isValid() const { -		return !_zero && payload.isValid() && isCRCcorrect(); +		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,11 +90,11 @@ 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; +	uint8_t command_id; // originally last_command_type  	uint32_t last_command_crc;  	uint8_t	last_command_status;  	union { @@ -186,8 +110,8 @@ struct DeviceResponse {  	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)); +		return misc::stm_crc32((const uint8_t *)(this) + 1, +							(size_t)(HID_REPORT_SIZE - 5));  	}  	void update_CRC() { @@ -199,7 +123,13 @@ struct DeviceResponse {  	}  	bool isValid() const { -		return !_zero && payload.isValid() && isCRCcorrect(); +//		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; @@ -209,6 +139,10 @@ struct EmptyPayload {  	bool isValid() const {  		return true;  	} + +	std::string dissect() const { +		return std::string("Empty Payload."); +	}  } __packed;  template<CommandID cmd_id, typename command_payload, @@ -220,10 +154,10 @@ public:  	typedef response_payload ResponsePayload;  	typedef struct HIDReport<cmd_id, CommandPayload> OutgoingPacket; -	typedef struct DeviceResponse<ResponsePayload> ResponsePacket; +	typedef struct DeviceResponse<cmd_id, ResponsePayload> ResponsePacket;  	static_assert(std::is_pod<OutgoingPacket>::value, -					"OutgoingPacket must be a POD type"); +					"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, @@ -233,7 +167,10 @@ public:  	static response_payload run(device::Device &dev,  			const command_payload &payload) { -		using namespace device; +		using namespace ::nitrokey::device; +		using namespace ::nitrokey::log; + +		Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2);  		CommError status;  		OutgoingPacket outp; @@ -246,6 +183,9 @@ public:  		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"); @@ -261,6 +201,9 @@ public:  				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"); @@ -274,782 +217,6 @@ public:  	}  }; -/* - *	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..db3186b --- /dev/null +++ b/include/dissect.h @@ -0,0 +1,60 @@ +/* + *	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; + +		out << "Raw HID packet:" << std::endl; +		out << ::nitrokey::misc::hexdump((const char *)(&pod), sizeof pod); + +		out << "Device status:\t" << 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 << 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..f6f7193 --- /dev/null +++ b/include/log.h @@ -0,0 +1,63 @@ +#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..bf68915 --- /dev/null +++ b/include/misc.h @@ -0,0 +1,15 @@ +#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..de31e95 --- /dev/null +++ b/include/stick10_commands.h @@ -0,0 +1,582 @@ +#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); +				} +			} __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); +				} +			} __packed; + +			typedef Transaction<command_id(), +								struct CommandPayload, +								struct EmptyPayload> 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; +				} +			} __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; +				} +			} __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); +				} +			} __packed; + +			struct ResponsePayload { +				uint8_t slot_name[PWS_SLOTNAME_LENGTH]; + +				bool isValid() const { +					return true; +				} +			} __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); +				} +			} __packed; + +			struct ResponsePayload { +				uint8_t slot_password[PWS_PASSWORD_LENGTH]; + +				bool isValid() const { +					return true; +				} +			} __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); +				} +			} __packed; + +			struct ResponsePayload { +				uint8_t slot_login[PWS_LOGINNAME_LENGTH]; + +				bool isValid() const { +					return true; +				} +			} __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; +				} +			} __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 { +				uint8_t crc[4]; +				uint8_t password[25]; +			} __packed; + +			typedef Transaction<command_id(), +									struct CommandPayload, +									struct EmptyPayload> CommandTransaction; +		}; + +		class UserAuthorize : Command<CommandID::USER_AUTHORIZE> { +		public: +			struct CommandPayload { +				uint8_t crc[4]; +				uint8_t password[25]; +			} __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..22b7e9a --- /dev/null +++ b/include/stick20_commands.h @@ -0,0 +1,249 @@ +#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 @@ -0,0 +1,44 @@ +#include <iostream> +#include <string> +#include <ctime> +#include <iomanip> +#include "log.h" + +namespace nitrokey { +namespace log { + +Log *Log::mp_instance = NULL; +StdlogHandler stdlog_handler; + +std::string LogHandler::loglevel_to_str(Loglevel lvl) { +	switch (lvl) { +		case Loglevel::DEBUG_L2: +			return std::string("DEBUG_L2"); +		case Loglevel::DEBUG: +			return std::string("DEBUG"); +		case Loglevel::INFO: +			return std::string("INFO"); +		case Loglevel::WARNING: +			return std::string("WARNING"); +		case Loglevel::ERROR: +			return std::string("ERROR"); +	} +	return std::string(""); +} + +void Log::operator()(const std::string &logstr, Loglevel lvl) { +	if (mp_loghandler != NULL) +		if ((int)(lvl) >= (int)(m_loglevel)) +			mp_loghandler->print(logstr, lvl); +} + +void StdlogHandler::print(const std::string &str, Loglevel lvl) { +    std::time_t t = std::time(nullptr); +    std::tm tm = *std::localtime(&t);  + +	std::clog << "[" << loglevel_to_str(lvl) << "] [" +			  << std::put_time(&tm, "%c %Z") <<  "]\t" << str << std::endl; +} + +} +} @@ -0,0 +1,51 @@ +#include <sstream> +#include <string> +#include "misc.h" +#include "inttypes.h" + +namespace nitrokey { +namespace misc { + +std::string hexdump(const char *p, size_t size) {  +	std::stringstream out; +	char formatbuf[128]; +	const char *pstart = p; + +	for (const char *pend = p + size; p < pend;) { +		snprintf(formatbuf, 128, "%04x\t", p - pstart); +		out << formatbuf; + +		for (const char *le = p + 16; p < le && p < pend; p++) { +			snprintf(formatbuf, 128, "%02x ", uint8_t(*p)); +			out << formatbuf; +		} +		out << std::endl; +	} +	return out.str(); +} + +static uint32_t _crc32 (uint32_t crc, uint32_t data) +{ +	int i; +    crc = crc ^ data; + +    for (i = 0; i < 32; i++) { +        if (crc & 0x80000000) +            crc = (crc << 1) ^ 0x04C11DB7;  // polynomial used in STM32 +        else +            crc = (crc << 1); +	} + +    return crc; +} + +uint32_t stm_crc32(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; +} + +} +} diff --git a/test.cc b/test.cc deleted file mode 100644 index 5c59c60..0000000 --- a/test.cc +++ /dev/null @@ -1,35 +0,0 @@ -#include <iostream> -#include <string.h> -#include "device_proto.h" -#include "device.h" - -using namespace std; - -using namespace device; -using namespace proto; -using namespace proto::stick10::command; - -int main() { -	Stick20 stick; -	cout << stick.connect() << endl; - -	{ -		auto resp = GetStatus::CommandTransaction::run(stick); -		cout << resp.firmware_version << endl; -	} - -	{ -		FirstAuthenticate::CommandTransaction::CommandPayload authreq; -		strcpy((char *)(authreq.card_password), "12345678"); -		FirstAuthenticate::CommandTransaction::run(stick, authreq); -	} - -	{ -	for (int i=0; i<32; i++) { -		GetSlotName::CommandTransaction::CommandPayload slotname_req; -		slotname_req.slot_number=i; -		auto slot_resp = GetSlotName::CommandTransaction::run(stick); -		cout << slot_resp.slot_name << endl; -	} -	} -} diff --git a/unittest/Makefile b/unittest/Makefile new file mode 100644 index 0000000..fb3f4ef --- /dev/null +++ b/unittest/Makefile @@ -0,0 +1,32 @@ +CC  = $(PREFIX)-gcc +CXX = $(PREFIX)-g++ +LD = $(CXX) + +INCLUDE = -I../include +LIB = -L../build +LDLIBS = -lhidapi-libusb -lnitrokey +BUILD = build + +CXXFLAGS = -std=c++14 -fPIC + +CXXSOURCES = $(wildcard *.cc) +TARGETS = $(CXXSOURCES:%.cc=$(BUILD)/%) +DEPENDS = $(CXXSOURCES:%.cc=$(BUILD)/%.d) + +$(BUILD)/%.d: %.cc +	$(CXX) -M $< -o $@ $(INCLUDE) $(CXXFLAGS) + +$(BUILD)/%: %.cc $(DEPENDS) +	$(CXX) $< -o $@ $(INCLUDE) $(LIB) $(CXXFLAGS) $(LDLIBS) + +all: $(TARGETS) + +clean: +	rm -f $(TARGETS) + +mrproper: clean +	rm -f $(BUILD)/*.d + +.PHONY: all clean mrproper + +include $(wildcard build/*.d) diff --git a/unittest/build/libnitrokey.so b/unittest/build/libnitrokey.so new file mode 120000 index 0000000..69a5e22 --- /dev/null +++ b/unittest/build/libnitrokey.so @@ -0,0 +1 @@ +../../build/libnitrokey.so
\ No newline at end of file diff --git a/unittest/test.cc b/unittest/test.cc new file mode 100644 index 0000000..c0762a5 --- /dev/null +++ b/unittest/test.cc @@ -0,0 +1,34 @@ +#include <iostream> +#include <string.h> +#include "device_proto.h" +#include "log.h" +#include "stick10_commands.h" + +using namespace std; +using namespace nitrokey::device; +using namespace nitrokey::proto::stick10; +using namespace nitrokey::log; + +int main() { +	Stick20 stick; + +	Log::instance().set_loglevel(Loglevel::DEBUG); + +	{ +		auto resp = GetStatus::CommandTransaction::run(stick); +	} + +	{ +		FirstAuthenticate::CommandTransaction::CommandPayload authreq; +		strcpy((char *)(authreq.card_password), "12345678"); +		FirstAuthenticate::CommandTransaction::run(stick, authreq); +	} + +	{ +		for (int i=0; i<10; i++) { +			ReadSlot::CommandTransaction::CommandPayload slot_req; +			slot_req.slot_number = i; +			auto slot = ReadSlot::CommandTransaction::run(stick, slot_req); +		} +	} +} | 
