From c4aec144256e3f27fedd8f8de03e10cc08eecab8 Mon Sep 17 00:00:00 2001 From: Mateusz Zalega Date: Thu, 22 Oct 2015 22:41:18 +0200 Subject: Initial --- include/crc32.h | 32 ++ include/cxx_semantics.h | 15 + include/device.h | 65 +++ include/device_proto.h | 1055 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1167 insertions(+) create mode 100644 include/crc32.h create mode 100644 include/cxx_semantics.h create mode 100644 include/device.h create mode 100644 include/device_proto.h (limited to 'include') diff --git a/include/crc32.h b/include/crc32.h new file mode 100644 index 0000000..b0e16ff --- /dev/null +++ b/include/crc32.h @@ -0,0 +1,32 @@ +/* + * 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 . + */ + +#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 new file mode 100644 index 0000000..f5d3dca --- /dev/null +++ b/include/cxx_semantics.h @@ -0,0 +1,15 @@ +#ifndef CXX_SEMANTICS_H +#define CXX_SEMANTICS_H + +#define __packed __attribute__((__packed__)) + +/* + * There's no need to include Boost for a simple subset this project needs. + */ +namespace semantics { + class non_constructible { + non_constructible() {} + }; +} + +#endif diff --git a/include/device.h b/include/device.h new file mode 100644 index 0000000..b2d83b5 --- /dev/null +++ b/include/device.h @@ -0,0 +1,65 @@ +#ifndef DEVICE_H +#define DEVICE_H +#include +#include +#include "inttypes.h" + +#define HID_REPORT_SIZE 65 + +// TODO !! SEMAPHORE + +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 +}; + +class Device { +public: + Device(); + + // 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); + + /* + * Gets packet of HID_REPORT_SIZE. + * Can sleep. See below. + */ + virtual CommError recv(void *packet); + +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; + + hid_device *mp_devhandle; +}; + +class Stick10 : public Device { +public: + Stick10(); +}; + +class Stick20 : public Device { +public: + Stick20(); +}; +} +#endif diff --git a/include/device_proto.h b/include/device_proto.h new file mode 100644 index 0000000..fb1dd4e --- /dev/null +++ b/include/device_proto.h @@ -0,0 +1,1055 @@ +#ifndef DEVICE_PROTO_H +#define DEVICE_PROTO_H +#include +#include +#include +#include +#include +// a local version for compatibility with Windows +#include "inttypes.h" +#include "cxx_semantics.h" +#include "device.h" +#include "utils/crc32.h" + +#define STICK20_UPDATE_MODE_VID 0x03EB +#define STICK20_UPDATE_MODE_PID 0x2FF1 + +#define PAYLOAD_SIZE 53 +#define PWS_SLOT_COUNT 16 +#define PWS_SLOTNAME_LENGTH 11 +#define PWS_PASSWORD_LENGTH 20 +#define PWS_LOGINNAME_LENGTH 32 + +#define PWS_SEND_PASSWORD 0 +#define PWS_SEND_LOGINNAME 1 +#define PWS_SEND_TAB 2 +#define PWS_SEND_CR 3 + +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 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. + * + * TODO (future) support for Big Endian + */ + +/* + * Every packet is a USB HID report (check USB spec) + */ +template +struct HIDReport { + uint8_t _zero; + CommandID command_id; // uint8_t + union { + uint8_t _padding[HID_REPORT_SIZE - 6]; + Payload payload; + } __packed; + uint32_t crc; + + // POD types can't have non-default constructors + // used in Transaction<>::run() + void initialize() { + bzero(this, sizeof *this); + command_id = cmd_id; + } + + uint32_t calculate_CRC() const { + // w/o leading zero, a part of each HID packet + // w/o 4-byte crc + return ::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(); + } +} __packed; + +/* + * Response payload (the parametrized type inside struct HIDReport) + * + * command_id member in incoming HIDReport structure carries the command + * type last used. + */ +template +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(); + } +} __packed; + +struct EmptyPayload { + uint8_t _data[]; + + bool isValid() const { + return true; + } +} __packed; + +template +class Transaction : semantics::non_constructible { +public: + // Types declared in command class scope can't be reached from there. + typedef command_payload CommandPayload; + typedef response_payload ResponsePayload; + + typedef struct HIDReport OutgoingPacket; + typedef struct DeviceResponse ResponsePacket; + + static_assert(std::is_pod::value, + "OutgoingPacket must be a POD type"); + static_assert(std::is_pod::value, + "ResponsePacket must be a POD type"); + static_assert(sizeof(OutgoingPacket) == HID_REPORT_SIZE, + "OutgoingPacket type is not the right size"); + static_assert(sizeof(ResponsePacket) == HID_REPORT_SIZE, + "ResponsePacket type is not the right size"); + + static 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); + } +}; + +/* + * 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 CommandTransaction; + }; + + class EraseSlot : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t slot_number; + + bool isValid() const { + return !(slot_number & 0xF0); + } + } __packed; + + typedef Transaction 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 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 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 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 CommandTransaction; + }; + + class GetHOTP : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t slot_number; + + bool isValid() const { + return !(slot_number & 0xF0); + } + } __packed; + + typedef Transaction 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 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 CommandTransaction; + }; + + class GetPasswordRetryCount : semantics::non_constructible { + public: + struct ResponsePayload { + uint8_t password_retry_count; + + bool isValid() const { + return true; + } + } __packed; + + typedef Transaction CommandTransaction; + }; + + class GetUserPasswordRetryCount : semantics::non_constructible { + public: + struct ResponsePayload { + uint8_t password_retry_count; + + bool isValid() const { + return true; + } + } __packed; + + typedef Transaction 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 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 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 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 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 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 CommandTransaction; + }; + + class ErasePasswordSafeSlot : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t slot_number; + + bool isValid() const { + return !(slot_number & 0xF0); + } + } __packed; + + typedef Transaction CommandTransaction; + }; + + class EnablePasswordSafe : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[30]; + + bool isValid() const { + return true; + } + } __packed; + + typedef Transaction CommandTransaction; + }; + + class PasswordSafeInitKey : semantics::non_constructible { + public: + typedef Transaction 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 CommandTransaction; + }; + + + // TODO "Device::passwordSafeSendSlotDataViaHID" + + class WriteGeneralConfig : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t config[5]; + } __packed; + + typedef Transaction 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 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 CommandTransaction; + }; + + class Authorize : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t crc[4]; + uint8_t password[25]; + } __packed; + + typedef Transaction CommandTransaction; + }; + + class UserAuthorize : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t crc[4]; + uint8_t password[25]; + } __packed; + + typedef Transaction 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 CommandTransaction; + }; + + class ChangeUserPin : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t old_pin[25]; + uint8_t new_pin[25]; + } __packed; + + typedef Transaction CommandTransaction; + }; + + // TODO why is it needed? + class IsAESSupported : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[20]; + } __packed; + + typedef Transaction CommandTransaction; + }; + + class ChangeAdminPin : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t old_pin[25]; + uint8_t new_pin[25]; + } __packed; + + typedef Transaction CommandTransaction; + }; + + class LockDevice : semantics::non_constructible { + public: + typedef Transaction CommandTransaction; + }; + + class FactoryReset : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[20]; + } __packed; + + typedef Transaction CommandTransaction; + }; + + class BuildAESKey : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[20]; + } __packed; + + typedef Transaction 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 CommandTransaction; + }; + + class DisableEncryptedPartition : semantics::non_constructible { + public: + typedef Transaction CommandTransaction; + }; + + class EnableHiddenEncryptedPartition : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[30]; // TODO check w/ firmware + }; + + typedef Transaction CommandTransaction; + }; + + class DisableHiddenEncryptedPartition : semantics::non_constructible { + public: + typedef Transaction CommandTransaction; + }; + + class EnableFirmwareUpdate : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[30]; // TODO check w/ firmware + }; + + typedef Transaction CommandTransaction; + }; + + class UpdatePassword : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t old_password[15]; + uint8_t new_password[15]; + }; + + typedef Transaction CommandTransaction; + }; + + class ExportFirmware : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[30]; + }; + + typedef Transaction CommandTransaction; + }; + + class CreateNewKeys : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[30]; + }; + + typedef Transaction CommandTransaction; + }; + + class FillSDCardWithRandomChars : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t volume_flag; + uint8_t password[30]; + }; + + typedef Transaction CommandTransaction; + }; + + class SetupHiddenVolume : semantics::non_constructible { + public: + typedef Transaction CommandTransaction; + }; + + class SendPasswordMatrix : semantics::non_constructible { + public: + typedef Transaction CommandTransaction; + }; + + class SendPasswordMatrixPinData : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t pin_data[30]; // TODO how long actually can it be? + }; + + typedef Transaction CommandTransaction; + }; + + class SendPasswordMatrixSetup : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t setup_data[30]; // TODO how long actually can it be? + }; + + typedef Transaction CommandTransaction; + }; + + class GetDeviceStatus : semantics::non_constructible { + public: + typedef Transaction CommandTransaction; + }; + + class SendPassword : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[30]; + }; + + typedef Transaction CommandTransaction; + }; + + class SendNewPassword : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[30]; + }; + + typedef Transaction CommandTransaction; + }; + + // TODO fix original nomenclature + class SendSetReadonlyToUncryptedVolume : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[30]; + }; + + typedef Transaction CommandTransaction; + }; + + class SendSetReadwriteToUncryptedVolume : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[30]; + }; + + typedef Transaction CommandTransaction; + }; + + class SendClearNewSdCardFound : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[30]; + }; + + typedef Transaction CommandTransaction; + }; + + class SendStartup : semantics::non_constructible { + public: + struct CommandPayload { + uint64_t localtime; // POSIX + }; + + typedef Transaction CommandTransaction; + }; + + class SendHiddenVolumeSetup : semantics::non_constructible { + public: + struct CommandPayload { + // TODO HiddenVolumeSetup_tst type + }; + + typedef Transaction CommandTransaction; + }; + + class LockFirmware : semantics::non_constructible { + public: + struct CommandPayload { + uint8_t password[30]; + }; + + typedef Transaction CommandTransaction; + }; + + class ProductionTest : semantics::non_constructible { + public: + typedef Transaction CommandTransaction; + }; + } +} +} + +#endif -- cgit v1.2.1