diff options
author | Szczepan Zalega <szczepan@nitrokey.com> | 2019-01-29 16:37:22 +0100 |
---|---|---|
committer | Szczepan Zalega <szczepan@nitrokey.com> | 2019-01-29 16:37:22 +0100 |
commit | 1bf90425d2006558ce4f4aac0ed5680d31b77918 (patch) | |
tree | c6789df5d10d1b5f6b83c5d1c7c2889e5ad2a6d9 | |
parent | b0d1d6a1a44210a25b3d0e6950ec08f551714ccf (diff) | |
parent | dc9dd81105634aeb100c47637fedef425f0ac6f9 (diff) | |
download | libnitrokey-1bf90425d2006558ce4f4aac0ed5680d31b77918.tar.gz libnitrokey-1bf90425d2006558ce4f4aac0ed5680d31b77918.tar.bz2 |
Merge branch 'pr_155'
Add Status structure, and a general command for using it as a result.
Usable to limit calls to the device, when multiple status fields are
required at given time.
Tested on Nitrokey Pro v0.7 and v0.10.
Run offline tests as well (C++ and Python).
Fixes #155
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | NK_C_API.cc | 28 | ||||
-rw-r--r-- | NK_C_API.h | 64 | ||||
-rw-r--r-- | unittest/test_multiple_devices.cc | 2 | ||||
-rw-r--r-- | unittest/test_pro.py | 18 | ||||
-rw-r--r-- | unittest/test_safe.cpp | 2 | ||||
-rw-r--r-- | unittest/test_strdup.cpp | 4 |
7 files changed, 111 insertions, 8 deletions
@@ -2,6 +2,7 @@ *.log *.o unittest/build/ +unittest/.pytest_cache/ *.pyc core .cache/ diff --git a/NK_C_API.cc b/NK_C_API.cc index eae35d5..e560c3f 100644 --- a/NK_C_API.cc +++ b/NK_C_API.cc @@ -252,6 +252,10 @@ extern "C" { NK_C_API char * NK_status() { + return NK_get_status_as_string(); + } + + NK_C_API char * NK_get_status_as_string() { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { string && s = m->get_status_as_string(); @@ -261,6 +265,30 @@ extern "C" { }); } + NK_C_API int NK_get_status(struct NK_status* out) { + if (out == nullptr) { + return -1; + } + auto m = NitrokeyManager::instance(); + auto result = get_with_status([&]() { + return m->get_status(); + }, proto::stick10::GetStatus::ResponsePayload()); + auto error_code = std::get<0>(result); + if (error_code != 0) { + return error_code; + } + + auto status = std::get<1>(result); + out->firmware_version_major = status.firmware_version_st.major; + out->firmware_version_minor = status.firmware_version_st.minor; + out->serial_number_smart_card = status.card_serial_u32; + out->config_numlock = status.numlock; + out->config_capslock = status.capslock; + out->config_scrolllock = status.scrolllock; + out->otp_user_password = status.enable_user_password != 0; + return 0; + } + NK_C_API char * NK_device_serial_number() { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { @@ -138,6 +138,47 @@ extern "C" { }; /** + * Stores the common device status for all Nitrokey devices. + */ + struct NK_status { + /** + * The major firmware version, e. g. 0 in v0.40. + */ + uint8_t firmware_version_major; + /** + * The minor firmware version, e. g. 40 in v0.40. + */ + uint8_t firmware_version_minor; + /** + * The serial number of the smart card. + */ + uint32_t serial_number_smart_card; + /** + * The HOTP slot to generate a password from if the numlock + * key is pressed twice (slot 0-1, or any other value to + * disable the function). + */ + uint8_t config_numlock; + /** + * The HOTP slot to generate a password from if the capslock + * key is pressed twice (slot 0-1, or any other value to + * disable the function). + */ + uint8_t config_capslock; + /** + * The HOTP slot to generate a password from if the scrolllock + * key is pressed twice (slot 0-1, or any other value to + * disable the function). + */ + uint8_t config_scrolllock; + /** + * Indicates whether the user password is required to generate + * an OTP value. + */ + bool otp_user_password; + }; + + /** * Stores the status of a Storage device. */ struct NK_storage_status { @@ -312,10 +353,31 @@ extern "C" { NK_C_API enum NK_device_model NK_get_device_model(); /** + * Return the debug status string. Debug purposes. This function is + * deprecated in favor of NK_get_status_as_string. + * @return string representation of the status or an empty string + * if the command failed + */ + DEPRECATED + NK_C_API char * NK_status(); + + /** * Return the debug status string. Debug purposes. + * @return string representation of the status or an empty string + * if the command failed + */ + NK_C_API char * NK_get_status_as_string(); + + /** + * Get the stick status common to all Nitrokey devices and return the + * command processing error code. If the code is zero, i. e. the + * command was successful, the storage status is written to the output + * pointer's target. The output pointer must not be null. + * + * @param out the output pointer for the status * @return command processing error code */ - NK_C_API char * NK_status(); + NK_C_API int NK_get_status(struct NK_status* out); /** * Return the device's serial number string in hex. diff --git a/unittest/test_multiple_devices.cc b/unittest/test_multiple_devices.cc index 4b1e2c1..7e10a42 100644 --- a/unittest/test_multiple_devices.cc +++ b/unittest/test_multiple_devices.cc @@ -117,7 +117,7 @@ TEST_CASE("Use C API", "[BASIC]") { while (ptr) { std::cout << "Connect with: " << ptr->model << " " << ptr->path << " " << ptr->serial_number << " | " << NK_connect_with_path(ptr->path) << " | "; - auto status = NK_status(); + auto status = NK_get_status_as_string(); std::cout << status << std::endl; free(status); ptr = ptr->next; diff --git a/unittest/test_pro.py b/unittest/test_pro.py index afa9505..6ab7c1d 100644 --- a/unittest/test_pro.py +++ b/unittest/test_pro.py @@ -674,11 +674,23 @@ def test_factory_reset(C): @pytest.mark.status -def test_get_status(C): - status = C.NK_status() +def test_get_status_as_string(C): + status = C.NK_get_status_as_string() s = gs(status) assert len(s) > 0 + +@pytest.mark.status +def test_get_status(C): + status_st = ffi.new('struct NK_status *') + if not status_st: + raise Exception("Could not allocate status") + err = C.NK_get_status(status_st) + assert err == 0 + assert status_st.firmware_version_major == 0 + assert status_st.firmware_version_minor != 0 + + @pytest.mark.status def test_get_serial_number(C): sn = C.NK_device_serial_number() @@ -926,4 +938,4 @@ 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
\ No newline at end of file + # assert C.NK_get_device_model() != C.NK_DISCONNECTED diff --git a/unittest/test_safe.cpp b/unittest/test_safe.cpp index d6f8b63..a244027 100644 --- a/unittest/test_safe.cpp +++ b/unittest/test_safe.cpp @@ -60,7 +60,7 @@ TEST_CASE("Status command for Pro or Storage", "[BASIC]") { auto const m = NK_get_device_model(); REQUIRE(m != NK_DISCONNECTED); if (m == NK_PRO) - s = NK_status(); + s = NK_get_status_as_string(); else if (m == NK_STORAGE){ s = NK_get_status_storage_as_string(); } diff --git a/unittest/test_strdup.cpp b/unittest/test_strdup.cpp index 4f77b7f..c7f4ea8 100644 --- a/unittest/test_strdup.cpp +++ b/unittest/test_strdup.cpp @@ -34,7 +34,7 @@ static const int SHORT_STRING_LENGTH = 10; TEST_CASE("Test strdup memory free error", "[BASIC]") { NK_set_debug(false); - char *c = NK_status(); /* error --> string literal */ + char *c = NK_get_status_as_string(); /* error --> string literal */ REQUIRE(c != nullptr); REQUIRE(strnlen(c, SHORT_STRING_LENGTH) == 0); puts(c); @@ -48,7 +48,7 @@ TEST_CASE("Test strdup memory leak", "[BASIC]") if (!connected) return; REQUIRE(connected); - char *c = NK_status(); /* no error --> dynamically allocated */ + char *c = NK_get_status_as_string(); /* no error --> dynamically allocated */ REQUIRE(c != nullptr); REQUIRE(strnlen(c, SHORT_STRING_LENGTH) > 0); puts(c); |