summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSzczepan Zalega <szczepan@nitrokey.com>2019-01-29 16:37:22 +0100
committerSzczepan Zalega <szczepan@nitrokey.com>2019-01-29 16:37:22 +0100
commit1bf90425d2006558ce4f4aac0ed5680d31b77918 (patch)
treec6789df5d10d1b5f6b83c5d1c7c2889e5ad2a6d9
parentb0d1d6a1a44210a25b3d0e6950ec08f551714ccf (diff)
parentdc9dd81105634aeb100c47637fedef425f0ac6f9 (diff)
downloadlibnitrokey-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--.gitignore1
-rw-r--r--NK_C_API.cc28
-rw-r--r--NK_C_API.h64
-rw-r--r--unittest/test_multiple_devices.cc2
-rw-r--r--unittest/test_pro.py18
-rw-r--r--unittest/test_safe.cpp2
-rw-r--r--unittest/test_strdup.cpp4
7 files changed, 111 insertions, 8 deletions
diff --git a/.gitignore b/.gitignore
index c98c3a9..7dd7cf8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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([&]() {
diff --git a/NK_C_API.h b/NK_C_API.h
index 47b2567..79d80c0 100644
--- a/NK_C_API.h
+++ b/NK_C_API.h
@@ -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);