1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
import pytest
import cffi
from enum import Enum
RFC_SECRET = '12345678901234567890'
class DefaultPasswords(Enum):
ADMIN = '12345678'
USER = '123456'
class DeviceErrorCode(Enum):
STATUS_OK = 0
NOT_PROGRAMMED = 3
WRONG_PASSWORD = 4
ffi = cffi.FFI()
@pytest.fixture(scope="module")
def C(request):
fp = '../NK_C_API.h'
declarations = []
with open(fp, 'r') as f:
declarations = f.readlines()
for declaration in declarations:
# extern int NK_write_totp_slot(int slot_number, char* secret, int time_window);
if 'extern' in declaration and not '"C"' in declaration:
declaration = declaration.replace('extern', '').strip()
print(declaration)
ffi.cdef(declaration)
C = ffi.dlopen("../build/libnitrokey.so")
C.NK_set_debug(False)
C.NK_login('12345678', '123123123')
# C.NK_set_debug(True)
def fin():
print ('\nFinishing connection to device')
C.NK_logout()
print ('Finished')
request.addfinalizer(fin)
return C
def test_enable_password_safe(C):
assert C.NK_enable_password_safe('wrong_password') == DeviceErrorCode.WRONG_PASSWORD
assert C.NK_enable_password_safe(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK
def test_password_safe_slot_status(C):
C.NK_set_debug(True)
assert C.NK_get_password_safe_slot_status() == DeviceErrorCode.STATUS_OK
C.NK_set_debug(False)
def test_admin_PIN_change(C):
assert C.NK_change_admin_PIN('wrong_password', '123123123') == DeviceErrorCode.WRONG_PASSWORD
assert C.NK_change_admin_PIN(DefaultPasswords.ADMIN, '123123123') == DeviceErrorCode.STATUS_OK
assert C.NK_change_admin_PIN('123123123', DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK
def test_user_PIN_change(C):
assert C.NK_change_user_PIN('wrong_password', '123123123') == DeviceErrorCode.WRONG_PASSWORD
assert C.NK_change_user_PIN(DefaultPasswords.USER, '123123123') == DeviceErrorCode.STATUS_OK
assert C.NK_change_user_PIN('123123123', DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK
def test_HOTP_RFC(C):
# https://tools.ietf.org/html/rfc4226#page-32
C.NK_write_hotp_slot(1, 'python_test', RFC_SECRET, 0, '123123123')
test_data = [
755224, 287082, 359152, 969429, 338314, 254676, 287922, 162583, 399871, 520489,
]
for code in test_data:
r = C.NK_get_hotp_code(1)
assert code == r
def test_TOTP_RFC(C):
# test according to https://tools.ietf.org/html/rfc6238#appendix-B
C.NK_write_totp_slot(1, 'python_test', RFC_SECRET, 30, True, '123123123')
test_data = [
(59, 1, 94287082),
(1111111109, 0x00000000023523EC, 7081804),
(1111111111, 0x00000000023523ED, 14050471),
(1234567890, 0x000000000273EF07, 89005924),
]
for t, T, code in test_data:
C.NK_totp_set_time(t)
r = C.NK_get_totp_code(1, T, 0, 30) # FIXME T is not changing the outcome
assert code == r
def test_get_slot_names(C):
# TODO add setup to have at least one slot not programmed
for i in range(16):
name = ffi.string(C.NK_get_totp_slot_name(i))
if name == '':
assert C.NK_get_last_command_status() == DeviceErrorCode.NOT_PROGRAMMED
for i in range(3):
name = ffi.string(C.NK_get_hotp_slot_name(i))
if name == '':
assert C.NK_get_last_command_status() == DeviceErrorCode.NOT_PROGRAMMED
def test_get_OTP_codes(C):
# TODO add setup to have at least one slot not programmed
for i in range(16):
code = C.NK_get_totp_code(i, 0, 0, 0)
if code == 0:
assert C.NK_get_last_command_status() == DeviceErrorCode.NOT_PROGRAMMED
for i in range(3):
code = C.NK_get_hotp_code(i)
if code == 0:
assert C.NK_get_last_command_status() == DeviceErrorCode.NOT_PROGRAMMED
|