summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.idea/vcs.xml2
-rw-r--r--NK_C_API.cc17
-rw-r--r--NK_C_API.h18
-rw-r--r--NitrokeyManager.cc14
-rw-r--r--command_id.cc4
-rw-r--r--libnitrokey/NitrokeyManager.h4
-rw-r--r--libnitrokey/command_id.h2
-rw-r--r--libnitrokey/misc.h16
-rw-r--r--libnitrokey/stick10_commands.h35
-rw-r--r--unittest/test_library.py2
-rw-r--r--unittest/test_pro.py27
11 files changed, 133 insertions, 8 deletions
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 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
+ <mapping directory="$PROJECT_DIR$/hidapi" vcs="Git" />
+ <mapping directory="$PROJECT_DIR$/unittest/Catch" vcs="Git" />
</component>
</project> \ No newline at end of file
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..9383cd9 100644
--- a/NK_C_API.h
+++ b/NK_C_API.h
@@ -977,6 +977,24 @@ extern "C" {
*/
NK_C_API int NK_wink();
+
+ /**
+ * 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
}
#endif
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<FirmwareUpdate>();
+ 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<FirmwarePasswordChange>();
+ strcpyT(p.firmware_password_current, firmware_pin_current);
+ strcpyT(p.firmware_password_new, firmware_pin_new);
+ FirmwarePasswordChange::CommandTransaction::run(device, p);
+ }
+
}
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/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);
};
}
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,
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);
}
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<CommandID::NEW_AES_KEY> {
};
+class FirmwareUpdate : Command<CommandID::FIRMWARE_UPDATE> {
+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<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+
+};
+
+class FirmwarePasswordChange : Command<CommandID::FIRMWARE_PASSWORD_CHANGE> {
+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<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+
+};
+
+
}
}
}
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 d094dec..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
@@ -939,3 +939,28 @@ 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):
+ 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
+
+
+@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
+
+
+@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