mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-23 00:57:26 +03:00
Use SCP11 when possible over NFC
This commit is contained in:
parent
c90ba130ce
commit
a25b5a279f
@ -31,18 +31,21 @@ from ykman.base import PID
|
|||||||
from ykman.device import scan_devices, list_all_devices
|
from ykman.device import scan_devices, list_all_devices
|
||||||
from ykman.diagnostics import get_diagnostics
|
from ykman.diagnostics import get_diagnostics
|
||||||
from ykman.logging import set_log_level
|
from ykman.logging import set_log_level
|
||||||
from yubikit.core import TRANSPORT
|
from yubikit.core import TRANSPORT, NotSupportedError
|
||||||
from yubikit.core.smartcard import SmartCardConnection, ApduError, SW
|
from yubikit.core.smartcard import SmartCardConnection, ApduError, SW
|
||||||
|
from yubikit.core.smartcard.scp import Scp11KeyParams
|
||||||
from yubikit.core.otp import OtpConnection
|
from yubikit.core.otp import OtpConnection
|
||||||
from yubikit.core.fido import FidoConnection
|
from yubikit.core.fido import FidoConnection
|
||||||
from yubikit.support import get_name, read_info
|
from yubikit.support import get_name, read_info
|
||||||
from yubikit.management import CAPABILITY
|
from yubikit.management import CAPABILITY
|
||||||
|
from yubikit.securitydomain import SecurityDomainSession
|
||||||
from yubikit.logging import LOG_LEVEL
|
from yubikit.logging import LOG_LEVEL
|
||||||
|
|
||||||
from ykman.pcsc import list_devices, YK_READER_NAME
|
from ykman.pcsc import list_devices, YK_READER_NAME
|
||||||
from smartcard.Exceptions import SmartcardException, NoCardException
|
from smartcard.Exceptions import SmartcardException, NoCardException
|
||||||
from smartcard.pcsc.PCSCExceptions import EstablishContextException
|
from smartcard.pcsc.PCSCExceptions import EstablishContextException
|
||||||
from smartcard.CardMonitoring import CardObserver, CardMonitor
|
from smartcard.CardMonitoring import CardObserver, CardMonitor
|
||||||
|
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from typing import Mapping, Tuple
|
from typing import Mapping, Tuple
|
||||||
@ -381,7 +384,7 @@ class ReaderDeviceNode(AbstractDeviceNode):
|
|||||||
try:
|
try:
|
||||||
connection = self._device.open_connection(SmartCardConnection)
|
connection = self._device.open_connection(SmartCardConnection)
|
||||||
info = read_info(connection)
|
info = read_info(connection)
|
||||||
return ConnectionNode(self._device, connection, info)
|
return ScpConnectionNode(self._device, connection, info)
|
||||||
except (ValueError, SmartcardException, EstablishContextException) as e:
|
except (ValueError, SmartcardException, EstablishContextException) as e:
|
||||||
logger.warning("Error opening connection", exc_info=True)
|
logger.warning("Error opening connection", exc_info=True)
|
||||||
raise ConnectionException(self._device.fingerprint, "ccid", e)
|
raise ConnectionException(self._device.fingerprint, "ccid", e)
|
||||||
@ -436,33 +439,36 @@ class ConnectionNode(RpcNode):
|
|||||||
self._info = read_info(self._connection, self._device.pid)
|
self._info = read_info(self._connection, self._device.pid)
|
||||||
return dict(version=self._info.version, serial=self._info.serial)
|
return dict(version=self._info.version, serial=self._info.serial)
|
||||||
|
|
||||||
|
def _init_child_node(self, child_cls):
|
||||||
|
return child_cls(self._connection)
|
||||||
|
|
||||||
@child(
|
@child(
|
||||||
condition=lambda self: self._transport == TRANSPORT.USB
|
condition=lambda self: self._transport == TRANSPORT.USB
|
||||||
or isinstance(self._connection, SmartCardConnection)
|
or isinstance(self._connection, SmartCardConnection)
|
||||||
)
|
)
|
||||||
def management(self):
|
def management(self):
|
||||||
return ManagementNode(self._connection)
|
return self._init_child_node(ManagementNode)
|
||||||
|
|
||||||
@child(
|
@child(
|
||||||
condition=lambda self: isinstance(self._connection, SmartCardConnection)
|
condition=lambda self: isinstance(self._connection, SmartCardConnection)
|
||||||
and CAPABILITY.OATH in self.capabilities
|
and CAPABILITY.OATH in self.capabilities
|
||||||
)
|
)
|
||||||
def oath(self):
|
def oath(self):
|
||||||
return OathNode(self._connection)
|
return self._init_child_node(OathNode)
|
||||||
|
|
||||||
@child(
|
@child(
|
||||||
condition=lambda self: isinstance(self._connection, SmartCardConnection)
|
condition=lambda self: isinstance(self._connection, SmartCardConnection)
|
||||||
and CAPABILITY.PIV in self.capabilities
|
and CAPABILITY.PIV in self.capabilities
|
||||||
)
|
)
|
||||||
def piv(self):
|
def piv(self):
|
||||||
return PivNode(self._connection)
|
return self._init_child_node(PivNode)
|
||||||
|
|
||||||
@child(
|
@child(
|
||||||
condition=lambda self: isinstance(self._connection, FidoConnection)
|
condition=lambda self: isinstance(self._connection, FidoConnection)
|
||||||
and CAPABILITY.FIDO2 in self.capabilities
|
and CAPABILITY.FIDO2 in self.capabilities
|
||||||
)
|
)
|
||||||
def ctap2(self):
|
def ctap2(self):
|
||||||
return Ctap2Node(self._connection)
|
return self._init_child_node(Ctap2Node)
|
||||||
|
|
||||||
@child(
|
@child(
|
||||||
condition=lambda self: CAPABILITY.OTP in self.capabilities
|
condition=lambda self: CAPABILITY.OTP in self.capabilities
|
||||||
@ -479,4 +485,27 @@ class ConnectionNode(RpcNode):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
def yubiotp(self):
|
def yubiotp(self):
|
||||||
return YubiOtpNode(self._connection)
|
return self._init_child_node(YubiOtpNode)
|
||||||
|
|
||||||
|
|
||||||
|
class ScpConnectionNode(ConnectionNode):
|
||||||
|
def __init__(self, device, connection, info):
|
||||||
|
super().__init__(device, connection, info)
|
||||||
|
|
||||||
|
self.scp_params = None
|
||||||
|
try:
|
||||||
|
scp = SecurityDomainSession(connection)
|
||||||
|
|
||||||
|
for ref in scp.get_key_information().keys():
|
||||||
|
if ref.kid == 0x13:
|
||||||
|
chain = scp.get_certificate_bundle(ref)
|
||||||
|
if chain:
|
||||||
|
pub_key = chain[-1].public_key()
|
||||||
|
assert isinstance(pub_key, EllipticCurvePublicKey) # nosec
|
||||||
|
self.scp_params = Scp11KeyParams(ref, pub_key)
|
||||||
|
break
|
||||||
|
except NotSupportedError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _init_child_node(self, child_cls):
|
||||||
|
return child_cls(self._connection, self.scp_params)
|
||||||
|
@ -28,10 +28,10 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class ManagementNode(RpcNode):
|
class ManagementNode(RpcNode):
|
||||||
def __init__(self, connection):
|
def __init__(self, connection, scp_params=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._connection_type: Type[Connection] = type(connection)
|
self._connection_type: Type[Connection] = type(connection)
|
||||||
self.session = ManagementSession(connection)
|
self.session = ManagementSession(connection, scp_params)
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
try:
|
try:
|
||||||
|
@ -77,9 +77,9 @@ class OathNode(RpcNode):
|
|||||||
logger.warning("Failed to unwrap access key", exc_info=True)
|
logger.warning("Failed to unwrap access key", exc_info=True)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __init__(self, connection):
|
def __init__(self, connection, scp_params=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.session = OathSession(connection)
|
self.session = OathSession(connection, scp_params)
|
||||||
self._key_verifier = None
|
self._key_verifier = None
|
||||||
|
|
||||||
if self.session.locked:
|
if self.session.locked:
|
||||||
|
@ -91,9 +91,9 @@ def _handle_pin_puk_error(e):
|
|||||||
|
|
||||||
|
|
||||||
class PivNode(RpcNode):
|
class PivNode(RpcNode):
|
||||||
def __init__(self, connection):
|
def __init__(self, connection, scp_params=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.session = PivSession(connection)
|
self.session = PivSession(connection, scp_params)
|
||||||
self._pivman_data = get_pivman_data(self.session)
|
self._pivman_data = get_pivman_data(self.session)
|
||||||
self._authenticated = False
|
self._authenticated = False
|
||||||
|
|
||||||
|
@ -40,9 +40,9 @@ _FAIL_MSG = (
|
|||||||
|
|
||||||
|
|
||||||
class YubiOtpNode(RpcNode):
|
class YubiOtpNode(RpcNode):
|
||||||
def __init__(self, connection):
|
def __init__(self, connection, scp_params=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.session = YubiOtpSession(connection)
|
self.session = YubiOtpSession(connection, scp_params)
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
state = self.session.get_config_state()
|
state = self.session.get_config_state()
|
||||||
|
Loading…
Reference in New Issue
Block a user