Skip to content
This repository was archived by the owner on Jun 9, 2022. It is now read-only.

Commit 7243107

Browse files
author
Venkat Venkataraju
committed
storing capability byte in the HIDDevice object
1 parent 2fdbadf commit 7243107

6 files changed

Lines changed: 115 additions & 4 deletions

File tree

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ addons:
2222

2323
install:
2424
- pip install "pip>=7.0.2" wheel
25-
- pip install -r dev-requirements.txt
25+
- $TRAVIS_BUILD_DIR/dev-requirements.py
2626
- pip install -e .
2727

2828
script:

dev-requirements-2.7.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
coverage
2+
coveralls
3+
Cython # For building hidapi in Tox and on Travis
4+
cryptography>=1.0
5+
mock

dev-requirements.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/usr/bin/env python
2+
3+
import os
4+
import sys
5+
6+
if sys.version_info.major == 2:
7+
os.system('pip install -r dev-requirements-2.7.txt')
8+
elif sys.version_info.major == 3:
9+
os.system('pip install -r dev-requirements-3.x.txt')
10+
else:
11+
raise Exception('Unsupported python version!')

test/test_hid_transport.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import os
2+
import unittest
3+
from u2flib_host import hid_transport
4+
from u2flib_host import exc
5+
from u2flib_host.yubicommon.compat import byte2int, int2byte
6+
from mock import patch
7+
8+
class TestHIDDevice():
9+
def write(self, payload):
10+
self.cid = payload[1:5]
11+
self.cmd = payload[5] ^ hid_transport.TYPE_INIT
12+
self.size = (payload[6] << 8) + payload[7]
13+
self.data = list(map(int2byte, payload[8:(8 + self.size)]))
14+
15+
def read(self, size):
16+
self.response += [0] * (hid_transport.HID_RPT_SIZE - len(self.response) + 1)
17+
types = list(map(type, self.response))
18+
return self.response
19+
20+
def close(self):
21+
return None
22+
23+
24+
class HIDDeviceTest(unittest.TestCase):
25+
@classmethod
26+
def build_response(cls, cid, cmd, data):
27+
size = len(data)
28+
size_low = size & 0xff
29+
size_high = (size >> 8) & 0xff
30+
response = list(map(byte2int, cid)) + list(map(byte2int, cmd)) + [size_high, size_low]
31+
response += list(map(byte2int, data))
32+
return response
33+
34+
35+
def test_init(self):
36+
with patch.object(os, 'urandom', return_value=(b'\xab'*8)) as mock_method:
37+
hid_device = TestHIDDevice()
38+
hid_device.response = HIDDeviceTest.build_response(
39+
b'\xff'*4,
40+
b'\x86',
41+
b'\xab'*8 + b'\x01\x02\x03\x04' + b'\x01\x02\x03\x04\x05'
42+
)
43+
44+
dev = hid_transport.HIDDevice('/dev/null')
45+
dev.handle = hid_device
46+
dev.init()
47+
self.assertEqual(dev.capabilities, 0x05)
48+
49+
def test_init_invalid_nounce(self):
50+
with patch.object(os, 'urandom', return_value=(b'\xab'*8)) as mock_method:
51+
hid_device = TestHIDDevice()
52+
hid_device.response = HIDDeviceTest.build_response(
53+
b'\xff'*4,
54+
b'\x86',
55+
b'\x00'*8 + b'\x01\x02\x03\x04' + b'\x01\x02\x03\x04\x05'
56+
)
57+
58+
dev = hid_transport.HIDDevice('/dev/null')
59+
dev.handle = hid_device
60+
with self.assertRaises(exc.DeviceError) as context:
61+
dev.init()
62+
self.assertTrue('Wrong INIT response from device' in context.exception)
63+
64+
def test_init_invalid_length(self):
65+
with patch.object(os, 'urandom', return_value=(b'\xab'*8)) as mock_method:
66+
hid_device = TestHIDDevice()
67+
hid_device.response = HIDDeviceTest.build_response(
68+
b'\xff'*4,
69+
b'\x86',
70+
b'\xab'*8 + b'\x01\x02\x03\x04' + b'\x01\x02\x03\x04'
71+
)
72+
73+
dev = hid_transport.HIDDevice('/dev/null')
74+
dev.handle = hid_device
75+
76+
with self.assertRaises(exc.DeviceError) as context:
77+
dev.init()
78+
self.assertTrue('Wrong INIT response from device' in context.exception)
79+
80+
def test_ctap2_enabled(self):
81+
dev = hid_transport.HIDDevice('/dev/null')
82+
dev.capabilities = 0x01
83+
self.assertFalse(dev.ctap2_enabled())
84+
dev.capabilities = 0x04
85+
self.assertTrue(dev.ctap2_enabled())

u2flib_host/hid_transport.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import hidraw as hid # Prefer hidraw
3333
except ImportError:
3434
import hid
35-
from time import time
35+
from time import time, sleep
3636
from u2flib_host.device import U2FDevice
3737
from u2flib_host.yubicommon.compat import byte2int, int2byte
3838
from u2flib_host import exc
@@ -110,6 +110,7 @@ class HIDDevice(U2FDevice):
110110
def __init__(self, path):
111111
self.path = path
112112
self.cid = b"\xff\xff\xff\xff"
113+
self.capabilities = 0x00
113114

114115
def open(self):
115116
self.handle = hid.device()
@@ -125,10 +126,19 @@ def close(self):
125126
def init(self):
126127
nonce = os.urandom(8)
127128
resp = self.call(CMD_INIT, nonce)
128-
while resp[:8] != nonce:
129-
print("Wrong nonce, read again...")
129+
130+
timeout = time() + 2.0
131+
while (len(resp) != 17 or resp[:8] != nonce):
132+
if timeout < time():
133+
raise exc.DeviceError('Wrong INIT response from device')
134+
sleep(0.1)
130135
resp = self._read_resp(self.cid, CMD_INIT)
136+
131137
self.cid = resp[8:12]
138+
self.capabilities = byte2int(resp[16])
139+
140+
def ctap2_enabled(self):
141+
return (self.capabilities >> 2) & 0x01
132142

133143
def set_mode(self, mode):
134144
data = mode + b"\x0f\x00\x00"

0 commit comments

Comments
 (0)