|
16 | 16 | from fido2.hid import CtapHidDevice, list_descriptors, open_device |
17 | 17 |
|
18 | 18 | try: |
| 19 | + from smartcard.CardConnection import CardConnection |
19 | 20 | from smartcard.ExclusiveConnectCardConnection import ExclusiveConnectCardConnection |
| 21 | + from smartcard.System import readers |
20 | 22 | except ModuleNotFoundError: |
21 | 23 |
|
22 | 24 | class ExclusiveConnectCardConnection: # type: ignore[no-redef] |
23 | 25 | pass |
24 | 26 |
|
| 27 | + class CardConnection: # type: ignore[no-redef] |
| 28 | + pass |
| 29 | + |
| 30 | + class Reader: |
| 31 | + pass |
| 32 | + |
| 33 | + def readers() -> list[Reader]: |
| 34 | + pass |
| 35 | + |
25 | 36 |
|
26 | 37 | from ._base import TrussedBase |
27 | 38 | from ._utils import Fido2Certs, Iso7816Apdu, Uuid |
@@ -154,7 +165,7 @@ def _call_admin_ccid_legacy( |
154 | 165 | def _call_ccid(self, app: App, response_len: Optional[int] = None, data: bytes = b"") -> bytes: |
155 | 166 | assert not isinstance(self.device, CtapHidDevice) |
156 | 167 | select = bytes([0x00, 0xA4, 0x04, 0x00, len(app.aid())]) + app.aid() |
157 | | - _, sw1, sw2 = self.device.transmit(list(select)) |
| 168 | + tmpbytes, sw1, sw2 = self.device.transmit(list(select)) |
158 | 169 | while True: |
159 | 170 | if sw1 == 0x61: |
160 | 171 | _, sw1, sw2 = self.device.transmit( |
@@ -211,6 +222,23 @@ def _call_app(self, app: App, response_len: Optional[int] = None, data: bytes = |
211 | 222 | @abstractmethod |
212 | 223 | def from_device(cls: type[T], device: CtapHidDevice | ExclusiveConnectCardConnection) -> T: ... |
213 | 224 |
|
| 225 | + @classmethod |
| 226 | + def clone(cls: type[T], device: type[T]) -> Optional[T]: |
| 227 | + """Clone the device, closing the previous connection first""" |
| 228 | + |
| 229 | + device.close() |
| 230 | + if isinstance(device.device, CtapHidDevice): |
| 231 | + new_device = cls.open(_device_path_to_str(device.device.descriptor.path)) |
| 232 | + return new_device |
| 233 | + else: |
| 234 | + reader = device.device.getReader() |
| 235 | + for r in readers(): |
| 236 | + if r.name == reader: |
| 237 | + connection = ExclusiveConnectCardConnection(r.createConnection()) |
| 238 | + connection.connect() |
| 239 | + return cls.from_device(connection) |
| 240 | + return None |
| 241 | + |
214 | 242 | @classmethod |
215 | 243 | def open(cls: type[T], path: str) -> Optional[T]: |
216 | 244 | try: |
|
0 commit comments