diff --git a/NK_C_API.cc b/NK_C_API.cc index c84e402..7fc784e 100644 --- a/NK_C_API.cc +++ b/NK_C_API.cc @@ -336,6 +336,38 @@ extern "C" { }); } + NK_C_API uint8_t NK_get_pws_slot_count() { + return NitrokeyManager::instance()->get_pws_slot_count(); + } + + NK_C_API size_t NK_get_pws_name_length() { + return NitrokeyManager::instance()->get_pws_name_length(); + } + + NK_C_API size_t NK_get_pws_login_length() { + return NitrokeyManager::instance()->get_pws_login_length(); + } + + NK_C_API size_t NK_get_pws_password_length() { + return NitrokeyManager::instance()->get_pws_password_length(); + } + + NK_C_API uint8_t NK_get_totp_slot_count() { + return NitrokeyManager::instance()->get_totp_slot_count(); + } + + NK_C_API uint8_t NK_get_hotp_slot_count() { + return NitrokeyManager::instance()->get_hotp_slot_count(); + } + + NK_C_API size_t NK_get_otp_name_length() { + return NitrokeyManager::instance()->get_otp_name_length(); + } + + NK_C_API size_t NK_get_otp_secret_length() { + return NitrokeyManager::instance()->get_otp_secret_length(); + } + NK_C_API char * NK_get_hotp_code(uint8_t slot_number) { return NK_get_hotp_code_PIN(slot_number, ""); } diff --git a/NK_C_API.h b/NK_C_API.h index 275f272..c2a6555 100644 --- a/NK_C_API.h +++ b/NK_C_API.h @@ -23,6 +23,7 @@ #define LIBNITROKEY_NK_C_API_H #include +#include #include #include "deprecated.h" @@ -527,6 +528,56 @@ extern "C" { */ NK_C_API int NK_read_config_struct(struct NK_config* out); + // OTP and PWS properties + + /** + * Returns the number of PWS slots provided by the connected device or + * zero if no device is connected. + */ + NK_C_API uint8_t NK_get_pws_slot_count(); + + /** + * Returns the maximum length of a PWS slot name in bytes for the + * connected device or zero if no device is connected. + */ + NK_C_API size_t NK_get_pws_name_length(); + + /** + * Returns the maximum length of a PWS login in bytes for the connected + * device or zero if no device is connected. + */ + NK_C_API size_t NK_get_pws_login_length(); + + /** + * Returns the maximum length of a PWS password in bytes for the + * connected device or zero if no device is connected. + */ + NK_C_API size_t NK_get_pws_password_length(); + + /** + * Returns the number of TOTP slots provided by the connected device or + * zero if no device is connected. + */ + NK_C_API uint8_t NK_get_totp_slot_count(); + + /** + * Returns the number of HOTP slots provided by the connected device or + * zero if no device is connected. + */ + NK_C_API uint8_t NK_get_hotp_slot_count(); + + /** + * Returns the maximum length of an OTP slot name in bytes for the + * connected device or zero if no device is connected. + */ + NK_C_API size_t NK_get_otp_name_length(); + + /** + * Returns the maximum length of an OTP secret in bytes for the + * connected device or zero if no device is connected. + */ + NK_C_API size_t NK_get_otp_secret_length(); + //OTP /** diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index 80b3537..123c575 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -390,6 +390,69 @@ using nitrokey::misc::strcpyT; } } + uint8_t NitrokeyManager::get_pws_slot_count() { + if (device == nullptr) { + return 0; + } else { + return PWS_SLOT_COUNT; + } + } + + size_t NitrokeyManager::get_pws_name_length() { + if (device == nullptr) { + return 0; + } else { + return PWS_SLOTNAME_LENGTH; + } + } + + size_t NitrokeyManager::get_pws_login_length() { + if (device == nullptr) { + return 0; + } else { + return PWS_LOGINNAME_LENGTH; + } + } + + size_t NitrokeyManager::get_pws_password_length() { + if (device == nullptr) { + return 0; + } else { + return PWS_PASSWORD_LENGTH; + } + } + + uint8_t NitrokeyManager::get_totp_slot_count() { + if (device == nullptr) { + return 0; + } else { + return TOTP_SLOT_COUNT; + } + } + + uint8_t NitrokeyManager::get_hotp_slot_count() { + if (device == nullptr) { + return 0; + } else { + return HOTP_SLOT_COUNT; + } + } + + size_t NitrokeyManager::get_otp_name_length() { + if (device == nullptr) { + return 0; + } else { + return OTP_SLOTNAME_LENGTH; + } + } + + size_t NitrokeyManager::get_otp_secret_length() { + if (device == nullptr) { + return 0; + } else { + return OTP_SECRET_LENGTH; + } + } string NitrokeyManager::get_serial_number() { try { @@ -470,8 +533,8 @@ using nitrokey::misc::strcpyT; } bool NitrokeyManager::is_internal_hotp_slot_number(uint8_t slot_number) const { return slot_number < 0x20; } - bool NitrokeyManager::is_valid_hotp_slot_number(uint8_t slot_number) const { return slot_number < 3; } - bool NitrokeyManager::is_valid_totp_slot_number(uint8_t slot_number) const { return slot_number < 0x10-1; } //15 + bool NitrokeyManager::is_valid_hotp_slot_number(uint8_t slot_number) const { return slot_number < HOTP_SLOT_COUNT; } + bool NitrokeyManager::is_valid_totp_slot_number(uint8_t slot_number) const { return slot_number < TOTP_SLOT_COUNT; } uint8_t NitrokeyManager::get_internal_slot_number_for_totp(uint8_t slot_number) const { return (uint8_t) (0x20 + slot_number); } uint8_t NitrokeyManager::get_internal_slot_number_for_hotp(uint8_t slot_number) const { return (uint8_t) (0x10 + slot_number); } @@ -636,9 +699,8 @@ using nitrokey::misc::strcpyT; payload2.id = 0; auto secret_bin = misc::hex_string_to_byte(secret); auto remaining_secret_length = secret_bin.size(); - const auto maximum_OTP_secret_size = 40; - if(remaining_secret_length > maximum_OTP_secret_size){ - throw TargetBufferSmallerThanSource(remaining_secret_length, maximum_OTP_secret_size); + if(remaining_secret_length > OTP_SECRET_LENGTH){ + throw TargetBufferSmallerThanSource(remaining_secret_length, OTP_SECRET_LENGTH); } while (remaining_secret_length>0){ diff --git a/libnitrokey/NitrokeyManager.h b/libnitrokey/NitrokeyManager.h index cb7cfce..e660f36 100644 --- a/libnitrokey/NitrokeyManager.h +++ b/libnitrokey/NitrokeyManager.h @@ -28,6 +28,7 @@ #include "stick10_commands.h" #include "stick10_commands_0.8.h" #include "stick20_commands.h" +#include #include #include #include @@ -64,6 +65,54 @@ char * strndup(const char* str, size_t maxlen); stick10::ReadSlot::ResponsePayload get_TOTP_slot_data(const uint8_t slot_number); stick10::ReadSlot::ResponsePayload get_HOTP_slot_data(const uint8_t slot_number); + /** + * Returns the number of PWS slots provided by the connected device or + * zero if no device is connected. + */ + uint8_t get_pws_slot_count(); + + /** + * Returns the maximum length of a PWS slot name in bytes for the + * connected device or zero if no device is connected. + */ + size_t get_pws_name_length(); + + /** + * Returns the maximum length of a PWS login in bytes for the connected + * device or zero if no device is connected. + */ + size_t get_pws_login_length(); + + /** + * Returns the maximum length of a PWS password in bytes for the + * connected device or zero if no device is connected. + */ + size_t get_pws_password_length(); + + /** + * Returns the number of TOTP slots provided by the connected device or + * zero if no device is connected. + */ + uint8_t get_totp_slot_count(); + + /** + * Returns the number of HOTP slots provided by the connected device or + * zero if no device is connected. + */ + uint8_t get_hotp_slot_count(); + + /** + * Returns the maximum length of an OTP slot name in bytes for the + * connected device or zero if no device is connected. + */ + size_t get_otp_name_length(); + + /** + * Returns the maximum length of an OTP secret in bytes for the + * connected device or zero if no device is connected. + */ + size_t get_otp_secret_length(); + bool set_time(uint64_t time); /** * Set the device time used for TOTP to the given time. Contrary to diff --git a/libnitrokey/device_proto.h b/libnitrokey/device_proto.h index 6ffe5fb..d39b104 100644 --- a/libnitrokey/device_proto.h +++ b/libnitrokey/device_proto.h @@ -52,6 +52,11 @@ #define PWS_SEND_TAB 2 #define PWS_SEND_CR 3 +#define HOTP_SLOT_COUNT 3 +#define TOTP_SLOT_COUNT 15 +#define OTP_SLOTNAME_LENGTH 15 +#define OTP_SECRET_LENGTH 40 + #include #include "DeviceCommunicationExceptions.h" #define bzero(b,len) (memset((b), '\0', (len)), (void) 0) diff --git a/unittest/test_offline.py b/unittest/test_offline.py index 51fe67d..0dfbd9f 100644 --- a/unittest/test_offline.py +++ b/unittest/test_offline.py @@ -36,4 +36,14 @@ def test_offline(C_offline): # v3.4.1-29-g1f3d search = re.search(b'v\d\.\d(\.\d)?', libnk_version) - assert search is not None \ No newline at end of file + assert search is not None + + assert C_offline.NK_get_pws_slot_count() == 0 + assert C_offline.NK_get_pws_name_length() == 0 + assert C_offline.NK_get_pws_login_length() == 0 + assert C_offline.NK_get_pws_password_length() == 0 + + assert C_offline.NK_get_hotp_slot_count() == 0 + assert C_offline.NK_get_totp_slot_count() == 0 + assert C_offline.NK_get_otp_name_length() == 0 + assert C_offline.NK_get_otp_secret_length() == 0 diff --git a/unittest/test_pro.py b/unittest/test_pro.py index 0d8c536..717affe 100644 --- a/unittest/test_pro.py +++ b/unittest/test_pro.py @@ -132,6 +132,14 @@ def test_password_safe_slot_status(C): assert is_slot_programmed[1] == 1 +@pytest.mark.PWS +def test_password_safe_properties(C): + assert C.NK_get_pws_slot_count() == 16 + assert C.NK_get_pws_name_length() == 11 + assert C.NK_get_pws_login_length() == 32 + assert C.NK_get_pws_password_length() == 20 + + @pytest.mark.aes def test_issue_device_locks_on_second_key_generation_in_sequence(C): # if is_pro_rtm_07(C) or is_pro_rtm_08(C): @@ -1070,3 +1078,11 @@ def test_OTP_all_rw(C): all_codes.append(this_loop_codes) from pprint import pprint pprint(all_codes) + + +@pytest.mark.otp +def test_otp_properties(C): + assert C.NK_get_hotp_slot_count() == 3 + assert C.NK_get_totp_slot_count() == 15 + assert C.NK_get_otp_name_length() == 15 + assert C.NK_get_otp_secret_length() == 40