/*
* Copyright (c) 2015-2018 Nitrokey UG
*
* This file is part of libnitrokey.
*
* libnitrokey is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* libnitrokey is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libnitrokey. If not, see .
*
* SPDX-License-Identifier: LGPL-3.0
*/
#ifndef STICK10_COMMANDS_H
#define STICK10_COMMANDS_H
#include
#include
#include
#include
#include
#include "device_proto.h"
#include "command.h"
#pragma pack (push,1)
namespace nitrokey {
namespace proto {
/*
* Stick10 protocol definition
*/
namespace stick10 {
class GetSlotName : public Command {
public:
// reachable as a typedef in Transaction
struct CommandPayload {
uint8_t slot_number;
bool isValid() const { return slot_number<0x10+3; }
std::string dissect() const {
std::stringstream ss;
ss << "slot_number:\t" << (int)(slot_number) << std::endl;
return ss.str();
}
} __packed;
struct ResponsePayload {
uint8_t slot_name[15];
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(slot_name);
return ss.str();
}
} __packed;
typedef Transaction CommandTransaction;
};
class EraseSlot : Command {
public:
struct CommandPayload {
uint8_t slot_number;
bool isValid() const { return !(slot_number & 0xF0); }
std::string dissect() const {
std::stringstream ss;
ss << "slot_number:\t" << (int)(slot_number) << std::endl;
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class SetTime : Command {
public:
struct CommandPayload {
uint8_t reset; // 0 - get time, 1 - set time
uint64_t time; // posix time
bool isValid() const { return reset && reset != 1; }
std::string dissect() const {
std::stringstream ss;
ss << "reset:\t" << (int)(reset) << std::endl;
ss << "time:\t" << (time) << std::endl;
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class WriteToHOTPSlot : Command {
public:
struct CommandPayload {
uint8_t slot_number;
uint8_t slot_name[15];
uint8_t slot_secret[20];
union{
uint8_t _slot_config;
struct{
bool use_8_digits : 1;
bool use_enter : 1;
bool use_tokenID : 1;
};
};
union{
uint8_t slot_token_id[13]; /** OATH Token Identifier */
struct{ /** @see https://openauthentication.org/token-specs/ */
uint8_t omp[2];
uint8_t tt[2];
uint8_t mui[8];
uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805
} slot_token_fields;
};
union{
uint64_t slot_counter;
uint8_t slot_counter_s[8];
} __packed;
bool isValid() const { return !(slot_number & 0xF0); }
std::string dissect() const {
std::stringstream ss;
ss << "slot_number:\t" << (int)(slot_number) << std::endl;
print_to_ss_volatile(slot_name);
print_to_ss_volatile(slot_secret);
ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
ss << "\tuse_enter(1):\t" << use_enter << std::endl;
ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
ss << "slot_token_id:\t";
for (auto i : slot_token_id)
ss << std::hex << std::setw(2) << std::setfill('0')<< (int) i << " " ;
ss << std::endl;
ss << "slot_counter:\t[" << (int)slot_counter << "]\t"
<< ::nitrokey::misc::hexdump((const uint8_t *)(&slot_counter), sizeof slot_counter, false);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class WriteToTOTPSlot : Command {
public:
struct CommandPayload {
uint8_t slot_number;
uint8_t slot_name[15];
uint8_t slot_secret[20];
union{
uint8_t _slot_config;
struct{
bool use_8_digits : 1;
bool use_enter : 1;
bool use_tokenID : 1;
};
};
union{
uint8_t slot_token_id[13]; /** OATH Token Identifier */
struct{ /** @see https://openauthentication.org/token-specs/ */
uint8_t omp[2];
uint8_t tt[2];
uint8_t mui[8];
uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805
} slot_token_fields;
};
uint16_t slot_interval;
bool isValid() const { return !(slot_number & 0xF0); } //TODO check
std::string dissect() const {
std::stringstream ss;
ss << "slot_number:\t" << (int)(slot_number) << std::endl;
print_to_ss_volatile(slot_name);
print_to_ss_volatile(slot_secret);
ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
ss << "slot_token_id:\t";
for (auto i : slot_token_id)
ss << std::hex << std::setw(2) << std::setfill('0')<< (int) i << " " ;
ss << std::endl;
ss << "slot_interval:\t" << (int)slot_interval << std::endl;
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class GetTOTP : Command {
public:
struct CommandPayload {
uint8_t slot_number;
uint64_t challenge;
uint64_t last_totp_time;
uint8_t last_interval;
bool isValid() const { return !(slot_number & 0xF0); }
std::string dissect() const {
std::stringstream ss;
ss << "slot_number:\t" << (int)(slot_number) << std::endl;
ss << "challenge:\t" << (challenge) << std::endl;
ss << "last_totp_time:\t" << (last_totp_time) << std::endl;
ss << "last_interval:\t" << (int)(last_interval) << std::endl;
return ss.str();
}
} __packed;
struct ResponsePayload {
union {
uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1
struct {
uint32_t code;
union{
uint8_t _slot_config;
struct{
bool use_8_digits : 1;
bool use_enter : 1;
bool use_tokenID : 1;
};
};
} __packed ;
} __packed ;
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
ss << "code:\t" << (code) << std::endl;
ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
ss << "\tuse_enter(1):\t" << use_enter << std::endl;
ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class GetHOTP : Command {
public:
struct CommandPayload {
uint8_t slot_number;
bool isValid() const { return (slot_number & 0xF0); }
std::string dissect() const {
std::stringstream ss;
ss << "slot_number:\t" << (int)(slot_number) << std::endl;
return ss.str();
}
} __packed;
struct ResponsePayload {
union {
uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1
struct {
uint32_t code;
union{
uint8_t _slot_config;
struct{
bool use_8_digits : 1;
bool use_enter : 1;
bool use_tokenID : 1;
};
};
} __packed;
} __packed;
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
ss << "code:\t" << (code) << std::endl;
ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
ss << "\tuse_enter(1):\t" << use_enter << std::endl;
ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class ReadSlot : Command {
public:
struct CommandPayload {
uint8_t slot_number;
bool isValid() const { return !(slot_number & 0xF0); }
std::string dissect() const {
std::stringstream ss;
ss << "slot_number:\t" << (int)(slot_number) << std::endl;
return ss.str();
}
} __packed;
struct ResponsePayload {
uint8_t slot_name[15];
union{
uint8_t _slot_config;
struct{
bool use_8_digits : 1;
bool use_enter : 1;
bool use_tokenID : 1;
};
};
union{
uint8_t slot_token_id[13]; /** OATH Token Identifier */
struct{ /** @see https://openauthentication.org/token-specs/ */
uint8_t omp[2];
uint8_t tt[2];
uint8_t mui[8];
uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805
} slot_token_fields;
};
union{
uint64_t slot_counter;
uint8_t slot_counter_s[8];
} __packed;
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(slot_name);
ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
ss << "\tuse_enter(1):\t" << use_enter << std::endl;
ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
ss << "slot_token_id:\t";
for (auto i : slot_token_id)
ss << std::hex << std::setw(2) << std::setfill('0')<< (int) i << " " ;
ss << std::endl;
ss << "slot_counter:\t[" << (int)slot_counter << "]\t"
<< ::nitrokey::misc::hexdump((const uint8_t *)(&slot_counter), sizeof slot_counter, false);
return ss.str();
}
} __packed;
typedef Transaction CommandTransaction;
};
class GetStatus : Command {
public:
struct ResponsePayload {
union {
uint16_t firmware_version;
struct {
uint8_t minor;
uint8_t major;
} firmware_version_st;
};
union{
uint8_t card_serial[4];
uint32_t card_serial_u32;
} __packed;
union {
uint8_t general_config[5];
struct{
uint8_t numlock; /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */
uint8_t capslock; /** same as numlock */
uint8_t scrolllock; /** same as numlock */
uint8_t enable_user_password;
uint8_t delete_user_password; /* unused */
} __packed;
} __packed;
static constexpr uint8_t special_HOTP_slots = 2;
bool isValid() const { return numlock < special_HOTP_slots && capslock < special_HOTP_slots
&& scrolllock < special_HOTP_slots && enable_user_password < 2; }
std::string get_card_serial_hex() const {
return nitrokey::misc::toHex(card_serial_u32);
}
std::string dissect() const {
std::stringstream ss;
ss << "firmware_version:\t"
<< "[" << firmware_version << "]" << "\t"
<< ::nitrokey::misc::hexdump(
(const uint8_t *)(&firmware_version), sizeof firmware_version, false);
ss << "card_serial_u32:\t" << std::hex << card_serial_u32 << std::endl;
ss << "card_serial:\t"
<< ::nitrokey::misc::hexdump((const uint8_t *)(card_serial),
sizeof card_serial, false);
ss << "general_config:\t"
<< ::nitrokey::misc::hexdump((const uint8_t *)(general_config),
sizeof general_config, false);
ss << "numlock:\t" << (int)numlock << std::endl;
ss << "capslock:\t" << (int)capslock << std::endl;
ss << "scrolllock:\t" << (int)scrolllock << std::endl;
ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl;
ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl;
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class GetPasswordRetryCount : Command {
public:
struct ResponsePayload {
uint8_t password_retry_count;
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
ss << " password_retry_count\t" << (int)password_retry_count << std::endl;
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class GetUserPasswordRetryCount
: Command {
public:
struct ResponsePayload {
uint8_t password_retry_count;
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
ss << " password_retry_count\t" << (int)password_retry_count << std::endl;
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
template
void write_array(T &ss, Q (&arr)[N]){
for (int i=0; i {
public:
struct ResponsePayload {
uint8_t password_safe_status[PWS_SLOT_COUNT];
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
ss << "password_safe_status\t";
write_array(ss, password_safe_status);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class GetPasswordSafeSlotName : Command {
public:
struct CommandPayload {
uint8_t slot_number;
bool isValid() const { return !(slot_number & 0xF0); }
std::string dissect() const {
std::stringstream ss;
ss << "slot_number\t" << (int)slot_number << std::endl;
return ss.str();
}
} __packed;
struct ResponsePayload {
uint8_t slot_name[PWS_SLOTNAME_LENGTH];
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(slot_name);
return ss.str();
}
} __packed;
typedef Transaction CommandTransaction;
};
class GetPasswordSafeSlotPassword
: Command {
public:
struct CommandPayload {
uint8_t slot_number;
bool isValid() const { return !(slot_number & 0xF0); }
std::string dissect() const {
std::stringstream ss;
ss << " slot_number\t" << (int)slot_number << std::endl;
return ss.str();
}
} __packed;
struct ResponsePayload {
uint8_t slot_password[PWS_PASSWORD_LENGTH];
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(slot_password);
return ss.str();
}
} __packed;
typedef Transaction CommandTransaction;
};
class GetPasswordSafeSlotLogin
: Command {
public:
struct CommandPayload {
uint8_t slot_number;
bool isValid() const { return !(slot_number & 0xF0); }
std::string dissect() const {
std::stringstream ss;
ss << " slot_number\t" << (int)slot_number << std::endl;
return ss.str();
}
} __packed;
struct ResponsePayload {
uint8_t slot_login[PWS_LOGINNAME_LENGTH];
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(slot_login);
return ss.str();
}
} __packed;
typedef Transaction CommandTransaction;
};
class SetPasswordSafeSlotData : Command {
public:
struct CommandPayload {
uint8_t slot_number;
uint8_t slot_name[PWS_SLOTNAME_LENGTH];
uint8_t slot_password[PWS_PASSWORD_LENGTH];
bool isValid() const { return !(slot_number & 0xF0); }
std::string dissect() const {
std::stringstream ss;
ss << " slot_number\t" << (int)slot_number << std::endl;
print_to_ss_volatile(slot_name);
print_to_ss_volatile(slot_password);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class SetPasswordSafeSlotData2 : Command {
public:
struct CommandPayload {
uint8_t slot_number;
uint8_t slot_login_name[PWS_LOGINNAME_LENGTH];
bool isValid() const { return !(slot_number & 0xF0); }
std::string dissect() const {
std::stringstream ss;
ss << " slot_number\t" << (int)slot_number << std::endl;
print_to_ss_volatile(slot_login_name);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class ErasePasswordSafeSlot : Command {
public:
struct CommandPayload {
uint8_t slot_number;
bool isValid() const { return !(slot_number & 0xF0); }
std::string dissect() const {
std::stringstream ss;
ss << " slot_number\t" << (int)slot_number << std::endl;
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class EnablePasswordSafe : Command {
public:
struct CommandPayload {
uint8_t user_password[30];
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(user_password);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class PasswordSafeInitKey : Command {
/**
* never used in Nitrokey App
*/
public:
typedef Transaction
CommandTransaction;
};
class PasswordSafeSendSlotViaHID : Command {
/**
* never used in Nitrokey App
*/
public:
struct CommandPayload {
uint8_t slot_number;
uint8_t slot_kind;
bool isValid() const { return !(slot_number & 0xF0); }
} __packed;
typedef Transaction
CommandTransaction;
};
// TODO "Device::passwordSafeSendSlotDataViaHID"
class WriteGeneralConfig : Command {
public:
struct CommandPayload {
union{
uint8_t config[5];
struct{
uint8_t numlock; /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */
uint8_t capslock; /** same as numlock */
uint8_t scrolllock; /** same as numlock */
uint8_t enable_user_password;
uint8_t delete_user_password;
};
};
bool isValid() const { return numlock < 2 && capslock < 2 && scrolllock < 2 && enable_user_password < 2; }
std::string dissect() const {
std::stringstream ss;
ss << "numlock:\t" << (int)numlock << std::endl;
ss << "capslock:\t" << (int)capslock << std::endl;
ss << "scrolllock:\t" << (int)scrolllock << std::endl;
ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl;
ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl;
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class FirstAuthenticate : Command {
public:
struct CommandPayload {
uint8_t card_password[25];
uint8_t temporary_password[25];
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(card_password);
hexdump_to_ss(temporary_password);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class UserAuthenticate : Command {
public:
struct CommandPayload {
uint8_t card_password[25];
uint8_t temporary_password[25];
bool isValid() const { return true; }
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(card_password);
hexdump_to_ss(temporary_password);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class Authorize : Command {
public:
struct CommandPayload {
uint32_t crc_to_authorize;
uint8_t temporary_password[25];
std::string dissect() const {
std::stringstream ss;
ss << " crc_to_authorize:\t" << std::hex << std::setw(2) << std::setfill('0') << crc_to_authorize<< std::endl;
hexdump_to_ss(temporary_password);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class UserAuthorize : Command {
public:
struct CommandPayload {
uint32_t crc_to_authorize;
uint8_t temporary_password[25];
std::string dissect() const {
std::stringstream ss;
ss << " crc_to_authorize:\t" << crc_to_authorize<< std::endl;
hexdump_to_ss(temporary_password);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class UnlockUserPassword : Command {
public:
struct CommandPayload {
uint8_t admin_password[25];
uint8_t user_new_password[25];
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(admin_password);
print_to_ss_volatile(user_new_password);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class ChangeUserPin : Command {
public:
struct CommandPayload {
uint8_t old_pin[25];
uint8_t new_pin[25];
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(old_pin);
print_to_ss_volatile(new_pin);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class IsAESSupported : Command {
public:
struct CommandPayload {
uint8_t user_password[20];
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(user_password);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class ChangeAdminPin : Command {
public:
struct CommandPayload {
uint8_t old_pin[25];
uint8_t new_pin[25];
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(old_pin);
print_to_ss_volatile(new_pin);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class LockDevice : Command {
public:
typedef Transaction
CommandTransaction;
};
class FactoryReset : Command {
public:
struct CommandPayload {
uint8_t admin_password[20];
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(admin_password);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
class BuildAESKey : Command {
public:
struct CommandPayload {
uint8_t admin_password[20];
std::string dissect() const {
std::stringstream ss;
print_to_ss_volatile(admin_password);
return ss.str();
}
} __packed;
typedef Transaction
CommandTransaction;
};
}
}
}
#pragma pack (pop)
#endif