Commit 059e466d authored by Scott Kitterman's avatar Scott Kitterman
Browse files

Update upstream source from tag 'upstream/3.5'

Update to upstream version '3.5'
with Debian dir 7c1c0f8c648848d684bdfef791b80054ac625f68
parents c2556b69 0ebbd886
......@@ -2,6 +2,7 @@
*.log
*.o
unittest/build/
unittest/.pytest_cache/
*.pyc
core
.cache/
......
[submodule "unittest/Catch"]
path = unittest/Catch
url = https://github.com/philsquared/Catch.git
url = https://github.com/catchorg/Catch2.git
[submodule "hidapi"]
path = hidapi
url = https://github.com/Nitrokey/hidapi.git
......@@ -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
......@@ -22,8 +22,20 @@ matrix:
- cmake
- libhidapi-dev
- g++-5
- python3
- python3-pip
- python3-requests
- git
sources: &sources
- ubuntu-toolchain-r-test
script:
- make -j2
- ctest -VV
- mkdir install && make install DESTDIR=install
- pip3 install pytest --user
- cd ../
- pip3 install -r unittest/requirements.txt --user
- cd unittest && python3 -m pytest -sv test_offline.py
- os: linux
dist: trusty
env: COMPILER_NAME=gcc CXX=g++-6 CC=gcc-6
......
......@@ -21,7 +21,7 @@ IF (UNIX)
ENDIF()
ENDIF()
project(libnitrokey LANGUAGES C CXX VERSION 3.4.1)
project(libnitrokey LANGUAGES C CXX VERSION 3.5.0)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
......@@ -130,9 +130,9 @@ execute_process(
)
ENDIF()
IF((NOT ${ADD_GIT_INFO}) OR (${PROJECT_VERSION_GIT_RETURN_CODE}))
SET(PROJECT_VERSION_GIT "unknown")
MESSAGE(STATUS "Setting Git library version to: " ${PROJECT_VERSION_GIT} )
SET(PROJECT_VERSION_GIT "v${PROJECT_VERSION}")
ENDIF()
MESSAGE(STATUS "Setting Git library version to: " ${PROJECT_VERSION_GIT} )
configure_file("version.cc.in" "version.cc" @ONLY)
......@@ -171,7 +171,7 @@ OPTION(COMPILE_OFFLINE_TESTS "Compile offline tests" FALSE)
IF(COMPILE_OFFLINE_TESTS OR COMPILE_TESTS)
find_package(PkgConfig)
IF(PKG_CONFIG_FOUND)
pkg_check_modules(CATCH2 catch)
pkg_check_modules(CATCH2 catch2)
ENDIF()
if (CATCH2_FOUND)
......@@ -211,6 +211,7 @@ IF (COMPILE_TESTS)
unittest/test_issues.cc
unittest/test_multiple_devices.cc
unittest/test_strdup.cpp
unittest/test_safe.cpp
)
foreach(testsourcefile ${TESTS} )
......@@ -232,3 +233,12 @@ set (CPACK_RESOURCE_FILE_LICENSE
"${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set (CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
include (CPack)
# Build Doxygen documentation for the C API
find_package(Doxygen)
if (DOXYGEN_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
add_custom_target(doc ${DOXYGEN_EXECUTABLE} Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating C API documentation with Doxygen" VERBATIM)
endif(DOXYGEN_FOUND)
# For better readability, the documentation and default settings are removed
# from this file. For more information on the Doxygen configuration, generate
# a new Doxyfile using `doxygen -g` or have a look at the Doxygen manual at
# http://www.doxygen.nl/manual/config.html
#
# This file is processed by CMake. To generate the documentation, run `make
# doc` in the build directory.
PROJECT_NAME = "@CMAKE_PROJECT_NAME@"
PROJECT_NUMBER = "@PROJECT_VERSION@"
PROJECT_BRIEF =
OUTPUT_DIRECTORY = doc
STRIP_FROM_PATH = @CMAKE_CURRENT_SOURCE_DIR@
JAVADOC_AUTOBRIEF = YES
OPTIMIZE_OUTPUT_FOR_C = YES
WARN_NO_PARAMDOC = YES
INPUT = @CMAKE_CURRENT_SOURCE_DIR@/NK_C_API.h
......@@ -27,7 +27,8 @@
#include "libnitrokey/LibraryException.h"
#include "libnitrokey/cxx_semantics.h"
#include "libnitrokey/stick20_commands.h"
#include "version.h"
#include "libnitrokey/device_proto.h"
#include "libnitrokey/version.h"
#ifdef _MSC_VER
#ifdef _WIN32
......@@ -44,6 +45,7 @@ char * strndup(const char* str, size_t maxlen) {
using namespace nitrokey;
const uint8_t NK_PWS_SLOT_COUNT = PWS_SLOT_COUNT;
static uint8_t NK_last_command_status = 0;
static const int max_string_field_length = 100;
......@@ -250,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();
......@@ -259,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([&]() {
......@@ -687,6 +717,23 @@ extern "C" {
return 0;
}
NK_C_API int NK_get_SD_usage_data(struct NK_SD_usage_data* out) {
if (out == nullptr)
return -1;
auto m = NitrokeyManager::instance();
auto result = get_with_status([&]() {
return m->get_SD_usage_data();
}, std::make_pair<uint8_t, uint8_t>(0, 0));
auto error_code = std::get<0>(result);
if (error_code != 0)
return error_code;
auto data = std::get<1>(result);
out->write_level_min = std::get<0>(data);
out->write_level_max = std::get<1>(data);
return 0;
}
NK_C_API char* NK_get_SD_usage_data_as_string() {
auto m = NitrokeyManager::instance();
......@@ -697,19 +744,19 @@ NK_C_API char* NK_get_SD_usage_data_as_string() {
NK_C_API int NK_get_progress_bar_value() {
auto m = NitrokeyManager::instance();
return get_with_result([&]() {
return std::get<1>(get_with_status([&]() {
return m->get_progress_bar_value();
});
}, -2));
}
NK_C_API int NK_get_major_firmware_version() {
NK_C_API uint8_t NK_get_major_firmware_version() {
auto m = NitrokeyManager::instance();
return get_with_result([&]() {
return m->get_major_firmware_version();
});
}
NK_C_API int NK_get_minor_firmware_version() {
NK_C_API uint8_t NK_get_minor_firmware_version() {
auto m = NitrokeyManager::instance();
return get_with_result([&]() {
return m->get_minor_firmware_version();
......@@ -736,6 +783,66 @@ NK_C_API char* NK_get_SD_usage_data_as_string() {
});
}
bool copy_device_info(const DeviceInfo& source, NK_device_info* target) {
switch (source.m_deviceModel) {
case DeviceModel::PRO:
target->model = NK_PRO;
break;
case DeviceModel::STORAGE:
target->model = NK_STORAGE;
break;
default:
return false;
}
target->path = strndup(source.m_path.c_str(), MAXIMUM_STR_REPLY_LENGTH);
target->serial_number = strndup(source.m_serialNumber.c_str(), MAXIMUM_STR_REPLY_LENGTH);
target->next = nullptr;
return target->path && target->serial_number;
}
NK_C_API struct NK_device_info* NK_list_devices() {
auto nm = NitrokeyManager::instance();
return get_with_result([&]() -> NK_device_info* {
auto v = nm->list_devices();
if (v.empty())
return nullptr;
auto result = new NK_device_info();
auto ptr = result;
auto first = v.begin();
if (!copy_device_info(*first, ptr)) {
NK_free_device_info(result);
return nullptr;
}
v.erase(first);
for (auto& info : v) {
ptr->next = new NK_device_info();
ptr = ptr->next;
if (!copy_device_info(info, ptr)) {
NK_free_device_info(result);
return nullptr;
}
}
return result;
});
}
NK_C_API void NK_free_device_info(struct NK_device_info* device_info) {
if (!device_info)
return;
if (device_info->next)
NK_free_device_info(device_info->next);
free(device_info->path);
free(device_info->serial_number);
delete device_info;
}
NK_C_API int NK_connect_with_ID(const char* id) {
auto m = NitrokeyManager::instance();
return get_with_result([&]() {
......@@ -743,6 +850,14 @@ NK_C_API char* NK_get_SD_usage_data_as_string() {
});
}
NK_C_API int NK_connect_with_path(const char* path) {
auto m = NitrokeyManager::instance();
return get_with_result([&]() {
return m->connect_with_path(path) ? 1 : 0;
});
}
NK_C_API int NK_wink() {
auto m = NitrokeyManager::instance();
return get_without_result([&]() {
......@@ -750,6 +865,46 @@ 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);
});
}
NK_C_API int NK_read_HOTP_slot(const uint8_t slot_num, struct ReadSlot_t* out){
if (out == nullptr)
return -1;
auto m = NitrokeyManager::instance();
auto result = get_with_status([&]() {
return m->get_HOTP_slot_data(slot_num);
}, stick10::ReadSlot::ResponsePayload() );
auto error_code = std::get<0>(result);
if (error_code != 0) {
return error_code;
}
#define a(x) out->x = read_slot.x
stick10::ReadSlot::ResponsePayload read_slot = std::get<1>(result);
a(_slot_config);
a(slot_counter);
#undef a
#define m(x) memmove(out->x, read_slot.x, sizeof(read_slot.x))
m(slot_name);
m(slot_token_id);
#undef m
return 0;
}
#ifdef __cplusplus
}
#endif
......@@ -33,10 +33,67 @@
#define NK_C_API
#endif
/**
* \file
*
* C API for libnitrokey
*
* \mainpage
*
* **libnitrokey** provides access to Nitrokey Pro and Nitrokey Storage devices.
* This documentation describes libnitrokey’s C API. For a list of the
* available functions, see the NK_C_API.h file.
*
* \section getting_started Example
*
* \code{.c}
* #include <stdio.h>
* #include <stdlib.h>
* #include <libnitrokey/NK_C_API.h>
*
* int main(void)
* {
* if (NK_login_auto() != 1) {
* fprintf(stderr, "No Nitrokey found.\n");
* return 1;
* }
*
* NK_device_model model = NK_get_device_model();
* printf("Connected to ");
* switch (model) {
* case NK_PRO:
* printf("a Nitrokey Pro");
* break;
* case NK_STORAGE:
* printf("a Nitrokey Storage");
* break;
* default:
* printf("an unsupported Nitrokey");
* break;
* }
*
* char* serial_number = NK_device_serial_number();
* if (serial_number)
* printf(" with serial number %s\n", serial_number);
* else
* printf(" -- could not query serial number!\n");
* free(serial_number);
*
* NK_logout();
* return 0;
* }
* \endcode
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* The number of slots in the password safe.
*/
extern const uint8_t NK_PWS_SLOT_COUNT;
static const int MAXIMUM_STR_REPLY_LENGTH = 8192;
/**
......@@ -57,6 +114,70 @@ extern "C" {
NK_STORAGE = 2
};
/**
* The connection info for a Nitrokey device as a linked list.
*/
struct NK_device_info {
/**
* The model of the Nitrokey device.
*/
enum NK_device_model model;
/**
* The USB device path for NK_connect_with_path.
*/
char* path;
/**
* The serial number.
*/
char* serial_number;
/**
* The pointer to the next element of the linked list or null
* if this is the last element in the list.
*/
struct NK_device_info* next;
};
/**
* 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.
*/
......@@ -128,6 +249,23 @@ extern "C" {
bool stick_initialized;
};
/**
* Data about the usage of the SD card.
*/
struct NK_SD_usage_data {
/**
* The minimum write level, as a percentage of the total card
* size.
*/
uint8_t write_level_min;
/**
* The maximum write level, as a percentage of the total card
* size.
*/
uint8_t write_level_max;
};
struct NK_storage_ProductionTest{
uint8_t FirmwareVersion_au8[2];
uint8_t FirmwareVersionInternal_u8;
......@@ -214,11 +352,32 @@ 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.
......@@ -528,13 +687,13 @@ extern "C" {
* Get device's major firmware version
* @return major part of the version number (e.g. 0 from 0.48, 0 from 0.7 etc.)
*/
NK_C_API int NK_get_major_firmware_version();
NK_C_API uint8_t NK_get_major_firmware_version();
/**
* Get device's minor firmware version
* @return minor part of the version number (e.g. 7 from 0.7, 48 from 0.48 etc.)
*/
NK_C_API int NK_get_minor_firmware_version();
NK_C_API uint8_t NK_get_minor_firmware_version();
/**
* Function to determine unencrypted volume PIN type
......@@ -736,6 +895,17 @@ extern "C" {
*/
NK_C_API int NK_get_status_storage(struct NK_storage_status* out);
/**
* Get SD card usage attributes. Usable during hidden volumes creation.
* If the command was successful (return value 0), the usage data is
* written to the output pointer’s target. The output pointer must
* not be null.
* Storage only
* @param out the output pointer for the usage data
* @return command processing error code
*/
NK_C_API int NK_get_SD_usage_data(struct NK_SD_usage_data* out);
/**
* Get SD card usage attributes as string.
* Usable during hidden volumes creation.
......@@ -747,7 +917,8 @@ extern "C" {
/**
* Get progress value of current long operation.
* Storage only
* @return int in range 0-100 or -1 if device is not busy
* @return int in range 0-100 or -1 if device is not busy or -2 if an
* error occured
*/
NK_C_API int NK_get_progress_bar_value();
......@@ -768,6 +939,19 @@ extern "C" {
*/
NK_C_API char* NK_list_devices_by_cpuID();
/**
* Returns a linked list of all connected devices, or null if no devices
* are connected or an error occured. The linked list must be freed by
* calling NK_free_device_info.
* @return a linked list of all connected devices
*/
NK_C_API struct NK_device_info* NK_list_devices();
/**
* Free a linked list returned by NK_list_devices.
* @param the linked list to free or null
*/
NK_C_API void NK_free_device_info(struct NK_device_info* device_info);
/**
* Connects to the device with given ID. ID's list could be created with NK_list_devices_by_cpuID.
......@@ -779,12 +963,50 @@ extern "C" {
*/
NK_C_API int NK_connect_with_ID(const char* id);
/**
* Connects to a device with the given path. The path is a USB device
* path as returned by hidapi.
* @param path the device path
* @return 1 on successful connection, 0 otherwise
*/
NK_C_API int NK_connect_with_path(const char* path);
/**
* Blink red and green LED alternatively and infinitely (until device is reconnected).
* @return command processing error code
*/
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);