From b6685dc2d7620a4de36dd76d833f800d0a2aaac6 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 13 Jun 2019 13:54:22 +0200 Subject: Add new command IDs Signed-off-by: Szczepan Zalega --- command_id.cc | 4 ++++ libnitrokey/command_id.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/command_id.cc b/command_id.cc index a6c2a28..9a329bc 100644 --- a/command_id.cc +++ b/command_id.cc @@ -71,6 +71,10 @@ const char *commandid_to_string(CommandID id) { return "CHANGE_USER_PIN"; case CommandID::CHANGE_ADMIN_PIN: return "CHANGE_ADMIN_PIN"; + case CommandID::FIRMWARE_UPDATE: + return "FIRMWARE_UPDATE"; + case CommandID::FIRMWARE_PASSWORD_CHANGE: + return "FIRMWARE_PASSWORD_CHANGE"; case CommandID::ENABLE_CRYPTED_PARI: return "ENABLE_CRYPTED_PARI"; diff --git a/libnitrokey/command_id.h b/libnitrokey/command_id.h index eb0d450..ee6726c 100644 --- a/libnitrokey/command_id.h +++ b/libnitrokey/command_id.h @@ -88,6 +88,8 @@ enum class CommandID : uint8_t { CHANGE_ADMIN_PIN = 0x15, WRITE_TO_SLOT_2 = 0x16, SEND_OTP_DATA = 0x17, + FIRMWARE_UPDATE = 0x19, + FIRMWARE_PASSWORD_CHANGE = 0x1A, ENABLE_CRYPTED_PARI = 0x20, DISABLE_CRYPTED_PARI = 0x20 + 1, -- cgit v1.2.1 From 5d0789af44ffdcdd7d3de30582fe51d1d2ceb22d Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 13 Jun 2019 13:55:36 +0200 Subject: Define commands structs Signed-off-by: Szczepan Zalega --- libnitrokey/stick10_commands.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/libnitrokey/stick10_commands.h b/libnitrokey/stick10_commands.h index f2ffba2..178b23f 100644 --- a/libnitrokey/stick10_commands.h +++ b/libnitrokey/stick10_commands.h @@ -882,6 +882,41 @@ class BuildAESKey : Command { }; +class FirmwareUpdate : Command { +public: + struct CommandPayload { + uint8_t firmware_password[20]; + std::string dissect() const { + std::stringstream ss; + print_to_ss_volatile(firmware_password); + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + +}; + +class FirmwarePasswordChange : Command { +public: + struct CommandPayload { + uint8_t firmware_password_current[20]; + uint8_t firmware_password_new[20]; + std::string dissect() const { + std::stringstream ss; + print_to_ss_volatile(firmware_password_current); + print_to_ss_volatile(firmware_password_new); + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + +}; + + } } } -- cgit v1.2.1 From 749434cab529ef689dacfc368b9dea101a40dba8 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 13 Jun 2019 13:56:02 +0200 Subject: Handle new commands in C++ API Signed-off-by: Szczepan Zalega --- NitrokeyManager.cc | 14 ++++++++++++++ libnitrokey/NitrokeyManager.h | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index 7b8deaa..ea409ef 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -1167,4 +1167,18 @@ using nitrokey::misc::strcpyT; return data.data(); }; + void NitrokeyManager::enable_firmware_update_pro(const char *firmware_pin) { + auto p = get_payload(); + strcpyT(p.firmware_password, firmware_pin); + FirmwareUpdate::CommandTransaction::run(device, p); + } + + void + NitrokeyManager::change_firmware_update_password_pro(const char *firmware_pin_current, const char *firmware_pin_new) { + auto p = get_payload(); + strcpyT(p.firmware_password_current, firmware_pin_current); + strcpyT(p.firmware_password_new, firmware_pin_new); + FirmwarePasswordChange::CommandTransaction::run(device, p); + } + } diff --git a/libnitrokey/NitrokeyManager.h b/libnitrokey/NitrokeyManager.h index 2d8d1b6..0691035 100644 --- a/libnitrokey/NitrokeyManager.h +++ b/libnitrokey/NitrokeyManager.h @@ -295,6 +295,10 @@ char * strndup(const char* str, size_t maxlen); void wink(); stick20::ProductionTest::ResponsePayload production_info(); + + void enable_firmware_update_pro(const char *firmware_pin); + + void change_firmware_update_password_pro(const char *firmware_pin_current, const char *firmware_pin_new); }; } -- cgit v1.2.1 From 35d73ac92b054d4b24b4fad3676001f29ee184a4 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 13 Jun 2019 13:56:25 +0200 Subject: Add calls to commands in C API Signed-off-by: Szczepan Zalega --- NK_C_API.cc | 17 +++++++++++++++++ NK_C_API.h | 9 +++++++++ 2 files changed, 26 insertions(+) diff --git a/NK_C_API.cc b/NK_C_API.cc index 844f653..ec7bc29 100644 --- a/NK_C_API.cc +++ b/NK_C_API.cc @@ -865,6 +865,23 @@ NK_C_API char* NK_get_SD_usage_data_as_string() { }); } + NK_C_API int NK_enable_firmware_update_pro(const char* update_password){ + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->enable_firmware_update_pro(update_password); + }); +} + + NK_C_API int NK_change_firmware_password_pro(const char *current_firmware_password, const char *new_firmware_password) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->change_firmware_update_password_pro(current_firmware_password, + new_firmware_password); + }); + } + + + #ifdef __cplusplus } #endif diff --git a/NK_C_API.h b/NK_C_API.h index 79d80c0..7376c9f 100644 --- a/NK_C_API.h +++ b/NK_C_API.h @@ -977,6 +977,15 @@ extern "C" { */ NK_C_API int NK_wink(); + + /** + * FIXME DOC + * @param update_password + * @return + */ + NK_C_API int NK_enable_firmware_update_pro(const char* update_password); + NK_C_API int NK_change_firmware_password_pro(const char *current_firmware_password, const char *new_firmware_password); + #ifdef __cplusplus } #endif -- cgit v1.2.1 From e46646d09c2167faf63e65c8557b4da820d152c2 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 13 Jun 2019 13:56:37 +0200 Subject: Add Python tests Signed-off-by: Szczepan Zalega --- unittest/test_pro.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/unittest/test_pro.py b/unittest/test_pro.py index d094dec..2d50c8e 100644 --- a/unittest/test_pro.py +++ b/unittest/test_pro.py @@ -939,3 +939,18 @@ def test_TOTP_codes_from_nitrokeyapp(secret, C): def test_get_device_model(C): assert C.NK_get_device_model() != 0 # assert C.NK_get_device_model() != C.NK_DISCONNECTED + + +@pytest.mark.firmware +def test_bootloader_password_change_pro(C): + assert C.NK_change_firmware_password_pro(b'zxcasd', b'zxcasd') == DeviceErrorCode.WRONG_PASSWORD + + assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE_TEMP, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK + + +@pytest.mark.firmware +def test_bootloader_run_pro(C): + assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.WRONG_PASSWORD + # Not enabled due to lack of side-effect removal at this point + # assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK -- cgit v1.2.1 From a0aae1fe26a6c68d6040c2dcf0194279e9c7007c Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 13 Jun 2019 13:57:11 +0200 Subject: Update IDE files Signed-off-by: Szczepan Zalega --- .idea/vcs.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..efdb874 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,7 @@ + + \ No newline at end of file -- cgit v1.2.1 From 00f168b909d5c7c61512d39ed170a0b799bc24c8 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Fri, 31 May 2019 21:53:18 +0200 Subject: Comments: fixme Signed-off-by: Szczepan Zalega --- unittest/test_pro.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/unittest/test_pro.py b/unittest/test_pro.py index 2d50c8e..83c6da3 100644 --- a/unittest/test_pro.py +++ b/unittest/test_pro.py @@ -947,10 +947,12 @@ def test_bootloader_password_change_pro(C): assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.STATUS_OK assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE_TEMP, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK - + # FIXME add tests for maximum password length + @pytest.mark.firmware def test_bootloader_run_pro(C): assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.WRONG_PASSWORD # Not enabled due to lack of side-effect removal at this point # assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK + # FIXME add tests for maximum password length \ No newline at end of file -- cgit v1.2.1 From a0efa194383f345cf266df933520ae0807a7e5b7 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 13 Jun 2019 13:46:02 +0200 Subject: Add exclusions to the Pro firmware tests Signed-off-by: Szczepan Zalega --- unittest/test_pro.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/unittest/test_pro.py b/unittest/test_pro.py index 83c6da3..dc21f0c 100644 --- a/unittest/test_pro.py +++ b/unittest/test_pro.py @@ -943,15 +943,18 @@ def test_get_device_model(C): @pytest.mark.firmware def test_bootloader_password_change_pro(C): + skip_if_device_version_lower_than({'P': 11}) + assert C.NK_change_firmware_password_pro(b'zxcasd', b'zxcasd') == DeviceErrorCode.WRONG_PASSWORD assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.STATUS_OK assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE_TEMP, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK # FIXME add tests for maximum password length - + @pytest.mark.firmware def test_bootloader_run_pro(C): + skip_if_device_version_lower_than({'P': 11}) assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.WRONG_PASSWORD # Not enabled due to lack of side-effect removal at this point # assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK -- cgit v1.2.1 From ae95a590a652cd17c82dbef4098ac496485c7cbd Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 13 Jun 2019 14:07:57 +0200 Subject: Add documentation of new commands to the C API Signed-off-by: Szczepan Zalega --- NK_C_API.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/NK_C_API.h b/NK_C_API.h index 7376c9f..9383cd9 100644 --- a/NK_C_API.h +++ b/NK_C_API.h @@ -979,11 +979,20 @@ extern "C" { /** - * FIXME DOC - * @param update_password - * @return + * Enable update mode on Nitrokey Pro. + * Supported from v0.11. + * @param update_password 20 bytes update password + * @return command processing error code */ NK_C_API int NK_enable_firmware_update_pro(const char* update_password); + + /** + * Change update-mode password on Nitrokey Pro. + * Supported from v0.11. + * @param current_firmware_password 20 bytes update password + * @param new_firmware_password 20 bytes update password + * @return command processing error code + */ NK_C_API int NK_change_firmware_password_pro(const char *current_firmware_password, const char *new_firmware_password); #ifdef __cplusplus -- cgit v1.2.1 From 0deddc2205b164cb775ff908265eebdf80943df2 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 13 Jun 2019 14:21:06 +0200 Subject: Add test for firmware password length Signed-off-by: Szczepan Zalega --- unittest/test_library.py | 2 ++ unittest/test_pro.py | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/unittest/test_library.py b/unittest/test_library.py index f6cf366..f26e587 100644 --- a/unittest/test_library.py +++ b/unittest/test_library.py @@ -41,6 +41,8 @@ def test_too_long_strings(C): long_string) == LibraryErrors.TOO_LONG_STRING assert gs(C.NK_get_hotp_code_PIN(0, long_string)) == b"" assert C.NK_get_last_command_status() == LibraryErrors.TOO_LONG_STRING + assert C.NK_change_firmware_password_pro(long_string, long_string) == LibraryErrors.TOO_LONG_STRING + assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, long_string) == LibraryErrors.TOO_LONG_STRING def test_invalid_slot(C): diff --git a/unittest/test_pro.py b/unittest/test_pro.py index dc21f0c..2930ed8 100644 --- a/unittest/test_pro.py +++ b/unittest/test_pro.py @@ -22,7 +22,7 @@ SPDX-License-Identifier: LGPL-3.0 import pytest from conftest import skip_if_device_version_lower_than -from constants import DefaultPasswords, DeviceErrorCode, RFC_SECRET, bb, bbRFC_SECRET +from constants import DefaultPasswords, DeviceErrorCode, RFC_SECRET, bb, bbRFC_SECRET, LibraryErrors from misc import ffi, gs, wait, cast_pointer_to_tuple, has_binary_counter from misc import is_pro_rtm_07, is_pro_rtm_08, is_storage @@ -944,12 +944,10 @@ def test_get_device_model(C): @pytest.mark.firmware def test_bootloader_password_change_pro(C): skip_if_device_version_lower_than({'P': 11}) - assert C.NK_change_firmware_password_pro(b'zxcasd', b'zxcasd') == DeviceErrorCode.WRONG_PASSWORD assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.STATUS_OK assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE_TEMP, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK - # FIXME add tests for maximum password length @pytest.mark.firmware @@ -958,4 +956,11 @@ def test_bootloader_run_pro(C): assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.WRONG_PASSWORD # Not enabled due to lack of side-effect removal at this point # assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK - # FIXME add tests for maximum password length \ No newline at end of file + + +@pytest.mark.firmware +def test_bootloader_password_change_pro_too_long(C): + skip_if_device_version_lower_than({'P': 11}) + long_string = b'a' * 100 + assert C.NK_change_firmware_password_pro(long_string, long_string) == LibraryErrors.TOO_LONG_STRING + assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, long_string) == LibraryErrors.TOO_LONG_STRING -- cgit v1.2.1 From 82e659779531a969155420f4f816b2458de3cfd5 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 13 Jun 2019 14:41:17 +0200 Subject: Use strnlen for field copies Signed-off-by: Szczepan Zalega --- libnitrokey/misc.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libnitrokey/misc.h b/libnitrokey/misc.h index d10c8df..a9c4672 100644 --- a/libnitrokey/misc.h +++ b/libnitrokey/misc.h @@ -67,7 +67,8 @@ private: oss << std::hex << std::setw(sizeof(value)*2) << std::setfill('0') << value; return oss.str(); } - + +#define FIELD_WIDTH_MAX (100) /** * Copies string from pointer to fixed size C-style array. Src needs to be a valid C-string - eg. ended with '\0'. * Throws when source is bigger than destination. @@ -82,12 +83,13 @@ private: // throw EmptySourceStringException(slot_number); return; const size_t s_dest = sizeof dest; - LOG(std::string("strcpyT sizes dest src ") - +std::to_string(s_dest)+ " " - +std::to_string(strlen(src))+ " " - ,nitrokey::log::Loglevel::DEBUG_L2); - if (strlen(src) > s_dest){ - throw TooLongStringException(strlen(src), s_dest, src); + const size_t src_strlen = strnlen(src, FIELD_WIDTH_MAX); + LOG(std::string("strcpyT sizes dest src ") + + std::to_string(s_dest) + " " + + std::to_string(src_strlen) + " " + , nitrokey::log::Loglevel::DEBUG_L2); + if (src_strlen > s_dest){ + throw TooLongStringException(src_strlen, s_dest, src); } strncpy((char*) &dest, src, s_dest); } -- cgit v1.2.1