diff --git a/src/inc/report_protocol.h b/src/inc/report_protocol.h
index c1273909..02952e16 100644
--- a/src/inc/report_protocol.h
+++ b/src/inc/report_protocol.h
@@ -18,7 +18,7 @@
* along with Nitrokey. If not, see .
*/
-#define FIRMWARE_VERSION 07
+#define FIRMWARE_VERSION (0x08)
#define CMD_GET_STATUS 0x00
#define CMD_WRITE_TO_SLOT 0x01
@@ -41,6 +41,7 @@
#define CMD_FACTORY_RESET 0x13
#define CMD_CHANGE_USER_PIN 0x14
#define CMD_CHANGE_ADMIN_PIN 0x15
+#define CMD_WRITE_TO_SLOT_2 0x16
#define CMD_GET_PW_SAFE_SLOT_STATUS 0x60
#define CMD_GET_PW_SAFE_SLOT_NAME 0x61
@@ -127,8 +128,9 @@
*/
-#define CMD_GC_SLOT_NUMBER_OFFSET 1
-#define CMD_GC_CHALLENGE_OFFSET 2
+#define CMD_GC_SLOT_NUMBER_OFFSET (1)
+#define CMD_GC_CHALLENGE_OFFSET (CMD_GC_SLOT_NUMBER_OFFSET + 1)
+#define CMD_GC_PASSWORD_OFFSET (CMD_GC_CHALLENGE_OFFSET + 8 + 8 + 1)
/*
* CMD_GET_PASSWORD_RETRY_COUNT
@@ -157,24 +159,9 @@
*/
-/*
- CMD_AUTHORIZE
-
- report: 1b command type 4b authorized crc 25b temporary password
-
-
- */
-
-
__IO extern uint8_t device_status;
-extern __IO uint8_t temp_password[25];
-
-extern __IO uint8_t tmp_password_set;
-
-extern __IO uint32_t authorized_crc;
-
uint8_t parse_report (uint8_t * report, uint8_t * output);
uint8_t cmd_get_status (uint8_t * report, uint8_t * output);
@@ -193,14 +180,10 @@ uint8_t cmd_erase_slot (uint8_t * report, uint8_t * output);
uint8_t cmd_first_authenticate (uint8_t * report, uint8_t * output);
-uint8_t cmd_authorize (uint8_t * report, uint8_t * output);
-
uint8_t cmd_get_password_retry_count (uint8_t * report, uint8_t * output);
uint8_t cmd_user_authenticate (uint8_t * report, uint8_t * output);
-uint8_t cmd_user_authorize (uint8_t * report, uint8_t * output);
-
uint8_t cmd_factory_reset (uint8_t * report, uint8_t * output);
uint8_t cmd_get_user_password_retry_count (uint8_t * report, uint8_t * output);
@@ -245,3 +228,75 @@ uint8_t cmd_getProDebug (uint8_t * report, uint8_t * output);
/*
uint8_t cmd_test_counter(uint8_t *report,uint8_t *output); uint8_t cmd_test_time(uint8_t *report,uint8_t *output); */
// END - OTP Test Routine ----------------------------------
+
+#define __packed __attribute__((__packed__))
+
+
+typedef struct {
+ uint8_t _command_type;
+ uint8_t temporary_admin_password[25];
+ 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;
+ };
+} __packed write_to_slot_1_payload;
+
+typedef struct {
+ uint8_t _command_type;
+ uint8_t temporary_admin_password[25];
+ uint8_t slot_number;
+ uint8_t slot_name[15];
+ union {
+ uint64_t slot_counter;
+ uint8_t slot_counter_s[8];
+ struct {
+ uint16_t slot_interval;
+ uint16_t __padding[3];
+ };
+ } __packed;
+} __packed write_to_slot_2_payload;
+
+typedef struct {
+ uint8_t _command_type;
+ 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;
+} __packed OTP_slot_content;
+
+static const int CMD_WRITE_CONFIG_PASSWORD_OFFSET = 6;
+static const int CMD_ERASE_SLOT_PASSWORD_OFFSET = 2;
\ No newline at end of file
diff --git a/src/keyboard/report_protocol.c b/src/keyboard/report_protocol.c
index 94b147f1..ceba5636 100644
--- a/src/keyboard/report_protocol.c
+++ b/src/keyboard/report_protocol.c
@@ -37,38 +37,27 @@
#include "time.h"
#include "password_safe.h"
-__IO uint8_t temp_password[25];
+uint8_t temp_password[25];
+uint8_t temp_user_password[25];
+bool temp_admin_password_set = FALSE;
+bool temp_user_password_set = FALSE;
-__IO uint8_t tmp_password_set = 0;
+OTP_slot_content local_slot_content;
-__IO uint32_t authorized_crc = 0xFFFFFFFF;
+bool write_to_slot_transaction_started = FALSE;
-__IO uint8_t temp_user_password[25];
+bool is_valid_temp_user_password(const uint8_t *const user_password);
+bool is_valid_admin_temp_password(const uint8_t *const password);
+bool is_user_PIN_protection_enabled(void);
+bool is_HOTP_slot_number(uint8_t slot_no);
+bool is_TOTP_slot_number(uint8_t slot_no);
-__IO uint8_t tmp_user_password_set = 0;
-
-__IO uint32_t authorized_user_crc = 0xFFFFFFFF;
-
-__IO uint32_t authorized_user_crc_set = 0;
-
-
-uint8_t parse_report(uint8_t *report, uint8_t *output) {
+uint8_t parse_report(uint8_t * const report, uint8_t * const output) {
uint8_t cmd_type = report[CMD_TYPE_OFFSET];
-
uint32_t received_crc32;
-
uint32_t calculated_crc32;
-
- uint8_t i;
-
uint8_t not_authorized = 0;
- // uint64_t counter=*((uint64_t *)(report+REPORT_COUNTER_VALUE_OFFSET));
-
-
-
- // received_crc32=((uint32_t *)report)[KEYBOARD_FEATURE_COUNT/4-1];
-
received_crc32 = getu32(report + KEYBOARD_FEATURE_COUNT - 4);
CRC_ResetDR();
calculated_crc32 = CRC_CalcBlockCRC((uint32_t *) report, KEYBOARD_FEATURE_COUNT / 4 - 1);
@@ -90,11 +79,31 @@ uint8_t parse_report(uint8_t *report, uint8_t *output) {
cmd_get_status(report, output);
break;
- case CMD_WRITE_TO_SLOT:
- if (calculated_crc32 == authorized_crc)
- cmd_write_to_slot(report, output);
- else
+ case CMD_WRITE_TO_SLOT_2: {
+ write_to_slot_2_payload const * const payload = (write_to_slot_2_payload*) report;
+ if(is_valid_admin_temp_password(payload->temporary_admin_password)
+ && write_to_slot_transaction_started == TRUE){
+ write_to_slot_transaction_started = FALSE;
+ local_slot_content.slot_number = payload->slot_number;
+ local_slot_content.slot_counter = payload->slot_counter;
+ memcpy(local_slot_content.slot_name, payload->slot_name, sizeof(payload->slot_name));
+ cmd_write_to_slot( (uint8_t*) &local_slot_content, output);
+ } else
not_authorized = 1;
+ }
+ break;
+
+ case CMD_WRITE_TO_SLOT: {
+ write_to_slot_1_payload const * const payload = (write_to_slot_1_payload*) report;
+ if(is_valid_admin_temp_password(payload->temporary_admin_password)) {
+ write_to_slot_transaction_started = TRUE;
+ memset((void *) &local_slot_content, 0, sizeof(local_slot_content));
+ local_slot_content._slot_config = payload->_slot_config;
+ memcpy(local_slot_content.slot_token_id, payload->slot_token_id, sizeof(payload->slot_token_id));
+ memcpy(local_slot_content.slot_secret, payload->slot_secret, sizeof(payload->slot_secret));
+ } else
+ not_authorized = 1;
+ }
break;
case CMD_READ_SLOT_NAME:
@@ -102,32 +111,27 @@ uint8_t parse_report(uint8_t *report, uint8_t *output) {
break;
case CMD_READ_SLOT:
- // if (calculated_crc32==authorized_crc)
cmd_read_slot(report, output);
- // else
- // not_authorized=1;
break;
- case CMD_GET_CODE:
- if ((authorized_user_crc_set
- && calculated_crc32 == authorized_user_crc) ||
- *((uint8_t *) (SLOTS_PAGE1_ADDRESS + GLOBAL_CONFIG_OFFSET + 3)) != 1) {
- authorized_user_crc = 0xFFFFFFFF;
- authorized_user_crc_set = 0;
- cmd_get_code(report, output);
- } else
- not_authorized = 1;
+ case CMD_GET_CODE: {
+ uint8_t *const user_temp_password = report + CMD_GC_PASSWORD_OFFSET;
+ if (!is_user_PIN_protection_enabled() || is_valid_temp_user_password(user_temp_password)) {
+ cmd_get_code(report, output);
+ } else
+ not_authorized = 1;
+ }
break;
case CMD_WRITE_CONFIG:
- if (calculated_crc32 == authorized_crc)
+ if (is_valid_admin_temp_password(report + CMD_WRITE_CONFIG_PASSWORD_OFFSET))
cmd_write_config(report, output);
else
not_authorized = 1;
break;
case CMD_ERASE_SLOT:
- if (calculated_crc32 == authorized_crc)
+ if (is_valid_admin_temp_password(report + CMD_ERASE_SLOT_PASSWORD_OFFSET))
cmd_erase_slot(report, output);
else
not_authorized = 1;
@@ -138,26 +142,17 @@ uint8_t parse_report(uint8_t *report, uint8_t *output) {
break;
case CMD_AUTHORIZE:
- cmd_authorize(report, output);
+ output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_UNKNOWN_COMMAND;
break;
case CMD_USER_AUTHORIZE:
- cmd_user_authorize(report, output);
+ output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_UNKNOWN_COMMAND;
break;
case CMD_GET_PASSWORD_RETRY_COUNT:
cmd_get_password_retry_count(report, output);
break;
- // FLASH_Unlock();
- // FLASH_ErasePage(oath_slots[slot]);
- // FLASH_ErasePage(oath_slots[slot]+COUNTER_PAGE_OFFSET);
-
- // write_data_to_flash(report+REPORT_COUNTER_VALUE_OFFSET,8,oath_slots[slot]+COUNTER_PAGE_OFFSET);
- // write_data_to_flash(report+REPORT_SECRET_VALUE_OFFSET,20,oath_slots[slot]+SECRET_OFFSET);
-
- // FLASH_Lock();
-
case CMD_GET_USER_PASSWORD_RETRY_COUNT:
cmd_get_user_password_retry_count(report, output);
break;
@@ -235,26 +230,15 @@ uint8_t parse_report(uint8_t *report, uint8_t *output) {
cmd_unblock_pin(report, output);
break;
- // START - OTP Test Routine --------------------------------
- /*
- case CMD_TEST_COUNTER: cmd_test_counter(report,output); break;
-
- case CMD_TEST_TIME: cmd_test_time(report,output); break; */
- // END - OTP Test Routine ----------------------------------
-
default: // Non of the above cases was selected => unknown
// command
output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_UNKNOWN_COMMAND;
break;
-
}
if (not_authorized)
output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_NOT_AUTHORIZED;
- if (calculated_crc32 == authorized_crc)
- authorized_crc = 0xFFFFFFFF;
-
} else
output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_WRONG_CRC;
@@ -269,6 +253,8 @@ uint8_t parse_report(uint8_t *report, uint8_t *output) {
return 0;
}
+bool is_user_PIN_protection_enabled(void) { return *((uint8_t *) (SLOTS_PAGE1_ADDRESS + GLOBAL_CONFIG_OFFSET + 3)) == 1; }
+
uint8_t cmd_get_status(uint8_t *report, uint8_t *output) {
output[OUTPUT_CMD_RESULT_OFFSET] = FIRMWARE_VERSION & 0xFF;
@@ -300,56 +286,47 @@ uint8_t cmd_get_user_password_retry_count(uint8_t *report, uint8_t *output) {
uint8_t cmd_write_to_slot(uint8_t *report, uint8_t *output) {
-
uint8_t slot_no = report[CMD_WTS_SLOT_NUMBER_OFFSET];
-
uint8_t slot_tmp[64]; // this is will be the new slot contents
- uint8_t slot_name[15];
-
memset(slot_tmp, 0, 64);
slot_tmp[0] = 0x01; // marks slot as programmed
- memcpy(slot_tmp + 1, report + CMD_WTS_SLOT_NAME_OFFSET, 51);
- memcpy(slot_name, report + CMD_WTS_SLOT_NAME_OFFSET, 15);
+ uint8_t *slot_name = report + CMD_WTS_SLOT_NAME_OFFSET;
+ memcpy(slot_tmp + 1, slot_name, 51);
if (slot_name[0] == 0) {
output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_NO_NAME_ERROR;
return 1;
}
- if (slot_no >= 0x10 && slot_no < 0x10 + NUMBER_OF_HOTP_SLOTS) { // HOTP slot
+ if (is_HOTP_slot_number(slot_no)) {
slot_no = slot_no & 0x0F;
-
uint64_t counter = getu64(report + CMD_WTS_COUNTER_OFFSET);
-
set_counter_value(hotp_slot_counters[slot_no], counter);
write_to_slot(slot_tmp, hotp_slot_offsets[slot_no], 64);
-
- } else if (slot_no >= 0x20 && slot_no < 0x20 + NUMBER_OF_TOTP_SLOTS) { // TOTP slot
+ } else if (is_TOTP_slot_number(slot_no)) {
slot_no = slot_no & 0x0F;
-
write_to_slot(slot_tmp, totp_slot_offsets[slot_no], 64);
-
} else {
output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_WRONG_SLOT;
-
-
}
return 0;
}
+bool is_TOTP_slot_number(uint8_t slot_no) { return slot_no >= 0x20 && slot_no < 0x20 + NUMBER_OF_TOTP_SLOTS; }
+
+bool is_HOTP_slot_number(uint8_t slot_no) { return slot_no >= 0x10 && slot_no < 0x10 + NUMBER_OF_HOTP_SLOTS; }
+
uint8_t cmd_read_slot_name(uint8_t *report, uint8_t *output) {
uint8_t slot_no = report[1];
- uint64_t counter;
-
- if (slot_no >= 0x10 && slot_no < 0x10 + NUMBER_OF_HOTP_SLOTS) { // HOTP slot
+ if (is_HOTP_slot_number(slot_no)) { // HOTP slot
slot_no = slot_no & 0x0F;
uint8_t is_programmed = *((uint8_t *) (hotp_slots[slot_no]));
@@ -359,7 +336,7 @@ uint8_t cmd_read_slot_name(uint8_t *report, uint8_t *output) {
output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_SLOT_NOT_PROGRAMMED;
}
- } else if (slot_no >= 0x20 && slot_no < 0x20 + NUMBER_OF_TOTP_SLOTS) { // TOTP slot
+ } else if (is_TOTP_slot_number(slot_no)) { // TOTP slot
slot_no = slot_no & 0x0F;
uint8_t is_programmed = *((uint8_t *) (totp_slots[slot_no]));
@@ -385,7 +362,7 @@ uint8_t cmd_read_slot(uint8_t *report, uint8_t *output) {
uint64_t counter;
- if (slot_no >= 0x10 && slot_no < 0x10 + NUMBER_OF_HOTP_SLOTS) { // HOTP slot
+ if (is_HOTP_slot_number(slot_no)) { // HOTP slot
slot_no = slot_no & 0x0F;
uint8_t is_programmed = *((uint8_t *) (hotp_slots[slot_no]));
@@ -399,7 +376,7 @@ uint8_t cmd_read_slot(uint8_t *report, uint8_t *output) {
output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_SLOT_NOT_PROGRAMMED;
}
- } else if (slot_no >= 0x20 && slot_no < 0x20 + NUMBER_OF_TOTP_SLOTS) { // TOTP slot
+ } else if (is_TOTP_slot_number(slot_no)) { // TOTP slot
slot_no = slot_no & 0x0F;
uint8_t is_programmed = *((uint8_t *) (totp_slots[slot_no]));
@@ -431,7 +408,7 @@ uint8_t cmd_get_code(uint8_t *report, uint8_t *output) {
uint8_t slot_no = report[CMD_GC_SLOT_NUMBER_OFFSET];
- if (slot_no >= 0x10 && slot_no < 0x10 + NUMBER_OF_HOTP_SLOTS) { // HOTP slot
+ if (is_HOTP_slot_number(slot_no)) { // HOTP slot
slot_no = slot_no & 0x0F;
uint8_t is_programmed = *((uint8_t *) (hotp_slots[slot_no]));
@@ -443,7 +420,7 @@ uint8_t cmd_get_code(uint8_t *report, uint8_t *output) {
} else
output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_SLOT_NOT_PROGRAMMED;
- } else if (slot_no >= 0x20 && slot_no < 0x20 + NUMBER_OF_TOTP_SLOTS) { // TOTP slot
+ } else if (is_TOTP_slot_number(slot_no)) { // TOTP slot
slot_no = slot_no & 0x0F;
uint8_t is_programmed = *((uint8_t *) (totp_slots[slot_no]));
@@ -467,7 +444,7 @@ uint8_t cmd_write_config(uint8_t *report, uint8_t *output) {
memset(slot_tmp, 0, 64);
- memcpy(slot_tmp, report + 1, 64);
+ memcpy(slot_tmp, report + 1, 5);
write_to_slot(slot_tmp, GLOBAL_CONFIG_OFFSET, 64);
@@ -485,13 +462,13 @@ uint8_t cmd_erase_slot(uint8_t *report, uint8_t *output) {
memset(slot_tmp, 0xFF, 64);
- if (slot_no >= 0x10 && slot_no < 0x10 + NUMBER_OF_HOTP_SLOTS) // HOTP
+ if (is_HOTP_slot_number(slot_no)) // HOTP
// slot
{
slot_no = slot_no & 0x0F;
write_to_slot(slot_tmp, hotp_slot_offsets[slot_no], 64);
erase_counter(slot_no);
- } else if (slot_no >= 0x20 && slot_no < 0x20 + NUMBER_OF_TOTP_SLOTS) // TOTP
+ } else if (is_TOTP_slot_number(slot_no)) // TOTP
// slot
{
slot_no = slot_no & 0x0F;
@@ -516,7 +493,7 @@ uint8_t cmd_first_authenticate(uint8_t *report, uint8_t *output) {
if (res == TRUE) {
memcpy(temp_password, report + 26, 25);
- tmp_password_set = 1;
+ temp_admin_password_set = TRUE;
getAID();
return 0;
} else {
@@ -539,7 +516,7 @@ uint8_t cmd_user_authenticate(uint8_t *report, uint8_t *output) {
if (res == 0) {
memcpy(temp_user_password, report + 26, 25);
- tmp_user_password_set = 1;
+ temp_user_password_set = TRUE;
getAID();
return 0;
} else {
@@ -644,42 +621,9 @@ uint8_t cmd_unblock_pin(uint8_t *report, uint8_t *output) {
}
}
-uint8_t cmd_authorize(uint8_t *report, uint8_t *output) {
+bool is_valid_admin_temp_password(const uint8_t *const password) { return temp_admin_password_set && memcmp(password, temp_password, 25) == 0; }
- if (tmp_password_set == 1) {
-
- if (memcmp(report + 5, temp_password, 25) == 0) {
- authorized_crc = getu32(report + 1);
- memset(temp_password, 0, sizeof(temp_password));
- tmp_password_set = 0;
- return 0;
- } else {
- output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_WRONG_PASSWORD;
- return 1;
- }
- }
-
- return 1;
-}
-
-uint8_t cmd_user_authorize(uint8_t *report, uint8_t *output) {
-
- if (tmp_user_password_set == 1) {
-
- if (memcmp(report + 5, temp_user_password, 25) == 0) {
- authorized_user_crc = getu32(report + 1);
- authorized_user_crc_set = 1;
- memset(temp_user_password, 0, sizeof(temp_user_password));
- tmp_user_password_set = 0;
- return 0;
- } else {
- output[OUTPUT_CMD_STATUS_OFFSET] = CMD_STATUS_WRONG_PASSWORD;
- return 1;
- }
- }
-
- return 1;
-}
+bool is_valid_temp_user_password(const uint8_t *const user_password) { return temp_user_password_set && memcmp(user_password, temp_user_password, 25) == 0; }
uint8_t cmd_factory_reset(uint8_t *report, uint8_t *output) {
@@ -918,8 +862,6 @@ uint8_t cmd_newAesKey(uint8_t *report, uint8_t *output) {
uint8_t cmd_getProDebug(uint8_t *report, uint8_t *output) {
- u32 ret;
-
unsigned char data[OUTPUT_CMD_RESULT_LENGTH];
unsigned int data_length = 0;
@@ -937,30 +879,3 @@ uint8_t cmd_lockDevice(uint8_t *report, uint8_t *output) {
PWS_DisableKey();
return 0;
}
-
-
-// START - OTP Test Routine --------------------------------
-/*
- uint8_t cmd_test_counter(uint8_t *report,uint8_t *output){
-
- int i; uint8_t slot_no = report[CMD_DATA_OFFSET]; uint16_t tests_number = getu16(report+CMD_DATA_OFFSET+1); uint16_t results = 0; uint64_t counter
- = get_counter_value(hotp_slot_counters[slot_no]); uint64_t counter_new = 0;
-
- for(i=0;i