From f6e09cc2fb4541a15a57415439b575d7bf44b07f Mon Sep 17 00:00:00 2001
From: Robin Krahl <me@robin-krahl.de>
Date: Fri, 25 May 2018 12:00:21 +0200
Subject: Refactor result retrieval in C API

The result retrieval functions get_with_array_result,
get_with_string_result, get_with_result and get_without_result currently
contain much duplicated code: the error handling.  This patch tries to
simplify this code by introducing a new function, get_with_status, that
executes a function, catches errors and returns the error code together
with the result of the function or a fallback value passed by the user
if the function failed.

get_with_array_result, get_with_string_result and get_with_result are
adapted to use this function.  get_without_result is not changed as it
has a different error handling logic than the other functions:  It
ignores any InvalidCRCReceived exceptions.
---
 NK_C_API.cc | 46 +++++++++++++++-------------------------------
 1 file changed, 15 insertions(+), 31 deletions(-)

diff --git a/NK_C_API.cc b/NK_C_API.cc
index 8e005b8..41c38aa 100644
--- a/NK_C_API.cc
+++ b/NK_C_API.cc
@@ -21,6 +21,7 @@
 
 #include "NK_C_API.h"
 #include <iostream>
+#include <tuple>
 #include "libnitrokey/NitrokeyManager.h"
 #include <cstring>
 #include "libnitrokey/LibraryException.h"
@@ -52,11 +53,11 @@ T* duplicate_vector_and_clear(std::vector<T> &v){
     return d;
 }
 
-template <typename T>
-uint8_t * get_with_array_result(T func){
+template <typename R, typename T>
+std::tuple<int, R> get_with_status(T func, R fallback) {
     NK_last_command_status = 0;
     try {
-        return func();
+        return std::make_tuple(0, func());
     }
     catch (CommandFailedException & commandFailedException){
         NK_last_command_status = commandFailedException.last_command_status;
@@ -67,43 +68,26 @@ uint8_t * get_with_array_result(T func){
     catch (const DeviceCommunicationException &deviceException){
       NK_last_command_status = 256-deviceException.getType();
     }
-    return nullptr;
+    return std::make_tuple(NK_last_command_status, fallback);
+}
+
+template <typename T>
+uint8_t * get_with_array_result(T func){
+    return std::get<1>(get_with_status<uint8_t*>(func, nullptr));
 }
 
 template <typename T>
 char* get_with_string_result(T func){
-    NK_last_command_status = 0;
-    try {
-        return func();
+    auto result = std::get<1>(get_with_status<char*>(func, nullptr));
+    if (result == nullptr) {
+        return strndup("", MAXIMUM_STR_REPLY_LENGTH);
     }
-    catch (CommandFailedException & commandFailedException){
-        NK_last_command_status = commandFailedException.last_command_status;
-    }
-    catch (LibraryException & libraryException){
-        NK_last_command_status = libraryException.exception_id();
-    }
-    catch (const DeviceCommunicationException &deviceException){
-      NK_last_command_status = 256-deviceException.getType();
-    }
-    return strndup("", MAXIMUM_STR_REPLY_LENGTH);
+    return result;
 }
 
 template <typename T>
 auto get_with_result(T func){
-    NK_last_command_status = 0;
-    try {
-        return func();
-    }
-    catch (CommandFailedException & commandFailedException){
-        NK_last_command_status = commandFailedException.last_command_status;
-    }
-    catch (LibraryException & libraryException){
-        NK_last_command_status = libraryException.exception_id();
-    }
-    catch (const DeviceCommunicationException &deviceException){
-      NK_last_command_status = 256-deviceException.getType();
-    }
-    return static_cast<decltype(func())>(0);
+    return std::get<1>(get_with_status(func, static_cast<decltype(func())>(0)));
 }
 
 template <typename T>
-- 
cgit v1.2.3


From 98917cffc50e7934105e874abd4a4b6ed72edc21 Mon Sep 17 00:00:00 2001
From: Robin Krahl <me@robin-krahl.de>
Date: Fri, 25 May 2018 12:15:08 +0200
Subject: Add getter for Storage status to C API

The C++ API currently provides the Storage status in
NitrokeyManager::get_status_storage().  The C API only provides a string
version of this data (NK_get_status_storage_as_string).  This patch adds
a struct to the C API that can store the storage status and a function
that can retrieve it.

The interpretation of the fields of the internal struct is based on the
following code in the Nitrokey Storage firmware:
    - src/HighLevelFunctions/FlashStorage.h, lines 73 to 90 (struct
      definition with comments)
    - src/OTP/report_protocol.c, lines 241 to 376 (debug output of the
      data)
---
 NK_C_API.cc | 34 +++++++++++++++++++++++++
 NK_C_API.h  | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 116 insertions(+)

diff --git a/NK_C_API.cc b/NK_C_API.cc
index 41c38aa..f6a6153 100644
--- a/NK_C_API.cc
+++ b/NK_C_API.cc
@@ -26,6 +26,7 @@
 #include <cstring>
 #include "libnitrokey/LibraryException.h"
 #include "libnitrokey/cxx_semantics.h"
+#include "libnitrokey/stick20_commands.h"
 
 #ifdef _MSC_VER
 #ifdef _WIN32
@@ -580,6 +581,39 @@ extern "C" {
 		});
 	}
 
+	NK_C_API int NK_get_status_storage(NK_storage_status* out) {
+		if (out == nullptr) {
+			return -1;
+		}
+		auto m = NitrokeyManager::instance();
+		auto result = get_with_status([&]() {
+			return m->get_status_storage();
+		}, proto::stick20::DeviceConfigurationResponsePacket::ResponsePayload());
+		auto error_code = std::get<0>(result);
+		if (error_code != 0) {
+			return error_code;
+		}
+
+		auto status = std::get<1>(result);
+		out->unencrypted_volume_read_only = status.ReadWriteFlagUncryptedVolume_u8 != 0;
+		out->unencrypted_volume_active = status.VolumeActiceFlag_st.unencrypted;
+		out->encrypted_volume_read_only = status.ReadWriteFlagCryptedVolume_u8 != 0;
+		out->encrypted_volume_active = status.VolumeActiceFlag_st.encrypted;
+		out->hidden_volume_read_only = status.ReadWriteFlagHiddenVolume_u8 != 0;
+		out->hidden_volume_active = status.VolumeActiceFlag_st.hidden;
+		out->firmware_version_major = status.versionInfo.major;
+		out->firmware_version_minor = status.versionInfo.minor;
+		out->firmware_locked = status.FirmwareLocked_u8 != 0;
+		out->serial_number_sd_card = status.ActiveSD_CardID_u32;
+		out->serial_number_smart_card = status.ActiveSmartCardID_u32;
+		out->user_retry_count = status.UserPwRetryCount;
+		out->admin_retry_count = status.AdminPwRetryCount;
+		out->new_sd_card_found = status.NewSDCardFound_st.NewCard;
+		out->filled_with_random = (status.SDFillWithRandomChars_u8 & 0x01) != 0;
+		out->stick_initialized = status.StickKeysNotInitiated == 0;
+		return 0;
+	}
+
 	NK_C_API char* NK_get_SD_usage_data_as_string() {
 		auto m = NitrokeyManager::instance();
 		return get_with_string_result([&]() {
diff --git a/NK_C_API.h b/NK_C_API.h
index 5985c0b..97169d1 100644
--- a/NK_C_API.h
+++ b/NK_C_API.h
@@ -51,6 +51,77 @@ extern "C" {
             NK_STORAGE
         };
 
+	/**
+	 * Stores the status of a Storage device.
+	 */
+        struct NK_storage_status {
+		/**
+		 * Indicates whether the unencrypted volume is read-only.
+		 */
+		bool unencrypted_volume_read_only;
+		/**
+		 * Indicates whether the unencrypted volume is active.
+		 */
+		bool unencrypted_volume_active;
+		/**
+		 * Indicates whether the encrypted volume is read-only.
+		 */
+		bool encrypted_volume_read_only;
+		/**
+		 * Indicates whether the encrypted volume is active.
+		 */
+		bool encrypted_volume_active;
+		/**
+		 * Indicates whether the hidden volume is read-only.
+		 */
+		bool hidden_volume_read_only;
+		/**
+		 * Indicates whether the hidden volume is active.
+		 */
+		bool hidden_volume_active;
+		/**
+		 * 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;
+		/**
+		 * Indicates whether the firmware is locked.
+		 */
+		bool firmware_locked;
+		/**
+		 * The serial number of the SD card in the Storage stick.
+		 */
+		uint32_t serial_number_sd_card;
+		/**
+		 * The serial number of the smart card in the Storage stick.
+		 */
+		uint32_t serial_number_smart_card;
+		/**
+		 * The number of remaining login attempts for the user PIN.
+		 */
+		uint8_t user_retry_count;
+		/**
+		 * The number of remaining login attempts for the admin PIN.
+		 */
+		uint8_t admin_retry_count;
+		/**
+		 * Indicates whether a new SD card was found.
+		 */
+		bool new_sd_card_found;
+		/**
+		 * Indicates whether the SD card is filled with random characters.
+		 */
+		bool filled_with_random;
+		/**
+		 * Indicates whether the stick has been initialized by generating
+		 * the AES keys.
+		 */
+		bool stick_initialized;
+        };
+
 	/**
 	 * Set debug level of messages written on stderr
 	 * @param state state=True - most messages, state=False - only errors level
@@ -586,6 +657,17 @@ extern "C" {
 	 */
 	NK_C_API char* NK_get_status_storage_as_string();
 
+	/**
+	 * Get the Storage stick status 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 storage status
+	 * @return command processing error code
+	 */
+	NK_C_API int NK_get_status_storage(NK_storage_status* out);
+
 	/**
 	 * Get SD card usage attributes as string.
 	 * Usable during hidden volumes creation.
-- 
cgit v1.2.3


From 5edb645227c00c63badc4fb3cccefa4d7e1bb547 Mon Sep 17 00:00:00 2001
From: Szczepan Zalega <szczepan@nitrokey.com>
Date: Tue, 19 Jun 2018 14:23:47 +0200
Subject: Add missing struct keyword

Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
---
 NK_C_API.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/NK_C_API.h b/NK_C_API.h
index 97169d1..274f908 100644
--- a/NK_C_API.h
+++ b/NK_C_API.h
@@ -666,7 +666,7 @@ extern "C" {
 	 * @param out the output pointer for the storage status
 	 * @return command processing error code
 	 */
-	NK_C_API int NK_get_status_storage(NK_storage_status* out);
+	NK_C_API int NK_get_status_storage(struct NK_storage_status* out);
 
 	/**
 	 * Get SD card usage attributes as string.
-- 
cgit v1.2.3