diff options
author | Szczepan Zalega <szczepan@nitrokey.com> | 2019-06-22 17:31:45 +0200 |
---|---|---|
committer | Szczepan Zalega <szczepan@nitrokey.com> | 2019-06-22 17:31:45 +0200 |
commit | 3ede630625cdc83cde2753897bee260595a5137a (patch) | |
tree | 578e349f9e5b44acabf106e3f8f8f2073a80ad02 | |
parent | 3fc4193776b4ea29354838df024a72d7c8349ea9 (diff) | |
parent | 1fed3fd903da061a58d846f92161b60b711d8df5 (diff) | |
download | libnitrokey-3ede630625cdc83cde2753897bee260595a5137a.tar.gz libnitrokey-3ede630625cdc83cde2753897bee260595a5137a.tar.bz2 |
Merge branch 'otp_tests'
Add OTP tests:
- complete writing and reading codes
- test edge slots of TOTP and HOTP
-rw-r--r-- | unittest/constants.py | 3 | ||||
-rw-r--r-- | unittest/test_pro.py | 91 |
2 files changed, 92 insertions, 2 deletions
diff --git a/unittest/constants.py b/unittest/constants.py index 714c8c6..645ef6a 100644 --- a/unittest/constants.py +++ b/unittest/constants.py @@ -57,3 +57,6 @@ class LibraryErrors: INVALID_HEX_STRING = 202 TARGET_BUFFER_SIZE_SMALLER_THAN_SOURCE = 203 + +HOTP_slot_count = 3 +TOTP_slot_count = 15
\ No newline at end of file diff --git a/unittest/test_pro.py b/unittest/test_pro.py index b8ae290..29eabff 100644 --- a/unittest/test_pro.py +++ b/unittest/test_pro.py @@ -22,9 +22,10 @@ SPDX-License-Identifier: LGPL-3.0 import pytest from conftest import skip_if_device_version_lower_than -from constants import DefaultPasswords, DeviceErrorCode, RFC_SECRET, bb, bbRFC_SECRET, LibraryErrors +from constants import DefaultPasswords, DeviceErrorCode, RFC_SECRET, bb, bbRFC_SECRET, LibraryErrors, HOTP_slot_count, \ + TOTP_slot_count from misc import ffi, gs, wait, cast_pointer_to_tuple, has_binary_counter -from misc import is_pro_rtm_07, is_pro_rtm_08, is_storage +from misc import is_storage @pytest.mark.lock_device @pytest.mark.PWS @@ -431,6 +432,10 @@ def test_HOTP_64bit_counter(C): lib_res += (t, lib_at(t)) assert dev_res == lib_res +def helper_set_HOTP_test_slot(C, slot_number): + assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_hotp_slot(slot_number, b'python_test', bbRFC_SECRET, 0, False, False, True, b'', DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + def helper_set_TOTP_test_slot(C, slot_number): PIN_protection = False @@ -593,6 +598,20 @@ def test_get_code_user_authorize(C): assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK +def helper_get_TOTP_code(C,i): + code = gs(C.NK_get_totp_code(i, 0, 0, 30)) + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK + assert code != b'' + return code + + +def helper_get_HOTP_code(C,i): + code = gs(C.NK_get_hotp_code(i)) + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK + assert code != b'' + return code + + @pytest.mark.otp def test_authorize_issue_admin(C): skip_if_device_version_lower_than({'S': 43, 'P': 9}) @@ -1003,3 +1022,71 @@ def test_HOTP_counter_getter(C, counter_mid: int): assert read_slot_st.slot_counter == counter +def test_edge_OTP_slots(C): + # -> shows TOTP15 is not written + # -> assuming HOTP1 is written + # (optional) Write slot HOTP1 + # Write slot TOTP15 + # Wait + # Read slot TOTP15 details + # Read HOTP1 details + # returns SLOT_NOT_PROGRAMMED + # (next nkapp execution) + # -> shows HOTP1 is not written + # briefly writing TOTP15 clears HOTP1, and vice versa + + read_slot_st = ffi.new('struct ReadSlot_t *') + if not read_slot_st: + raise Exception("Could not allocate status") + use_pin_protection = False + use_8_digits = False + assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_config(255, 255, 255, use_pin_protection, not use_pin_protection, + DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + counter = 0 + HOTP_slot_number = 1 -1 + TOTP_slot_number = 15 -1 # 0 based + assert C.NK_write_totp_slot(TOTP_slot_number, b'python_test', bbRFC_SECRET, 30, False, False, False, b'', + DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_hotp_slot(HOTP_slot_number, b'python_test', bbRFC_SECRET, counter, use_8_digits, False, False, b'', DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + for i in range(5): + code_hotp = gs(C.NK_get_hotp_code(HOTP_slot_number)) + assert code_hotp + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK + assert C.NK_read_HOTP_slot(HOTP_slot_number, read_slot_st) == DeviceErrorCode.STATUS_OK + assert read_slot_st.slot_counter == (i+1) + helper_set_time_on_device(C, 1) + code_totp = gs((C.NK_get_totp_code(TOTP_slot_number, 0, 0, 30))) + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK + + +def test_OTP_all_rw(C): + """ + Write all OTP slots and read codes from them two times. + All generated codes should be the same, which is checked as well. + """ + for i in range(TOTP_slot_count): + helper_set_TOTP_test_slot(C, i) + for i in range(HOTP_slot_count): + helper_set_HOTP_test_slot(C, i) + all_codes = [] + for i in range(5): + this_loop_codes = [] + code_old = b'' + helper_set_time_on_device(C, 30*i) + for i in range(TOTP_slot_count): + code = helper_get_TOTP_code(C, i) + if code_old: + assert code == code_old + code_old = code + this_loop_codes.append(('T', i, code)) + code_old = b'' + for i in range(HOTP_slot_count): + code = helper_get_HOTP_code(C, i) + if code_old: + assert code == code_old + code_old = code + this_loop_codes.append(('H', i, code)) + all_codes.append(this_loop_codes) + from pprint import pprint + pprint(all_codes)
\ No newline at end of file |