def _read_info_ctap(conn, key_type, interfaces): try: mgmt = ManagementSession(conn) return mgmt.read_device_info() except Exception: # SKY 1 or NEO version = (3, 0, 0) # Guess, no way to know supported_apps = {TRANSPORT.USB: CAPABILITY.U2F} if key_type == YUBIKEY.NEO: supported_apps[TRANSPORT.USB] |= BASE_NEO_APPS supported_apps[TRANSPORT.NFC] = supported_apps[TRANSPORT.USB] return DeviceInfo( config=DeviceConfig( enabled_capabilities={}, # Populated later auto_eject_timeout=0, challenge_response_timeout=0, device_flags=0, ), serial=None, version=version, form_factor=FORM_FACTOR.USB_A_KEYCHAIN, supported_capabilities=supported_apps, is_locked=False, )
def _read_info_ctap(conn, key_type, interfaces): try: mgmt = ManagementSession(conn) return mgmt.read_device_info() except Exception: # SKY 1 or NEO version = (3, 0, 0) # Guess, no way to know enabled_apps = {TRANSPORT.USB: APPLICATION.U2F} if USB_INTERFACE.CCID in interfaces: enabled_apps[TRANSPORT.USB] |= ( APPLICATION.OPGP | APPLICATION.PIV | APPLICATION.OATH ) if USB_INTERFACE.OTP in interfaces: enabled_apps[TRANSPORT.USB] |= APPLICATION.OTP supported_apps = {TRANSPORT.USB: APPLICATION.U2F} if key_type == YUBIKEY.NEO: supported_apps[TRANSPORT.USB] |= BASE_NEO_APPS supported_apps[TRANSPORT.NFC] = supported_apps[TRANSPORT.USB] enabled_apps[TRANSPORT.NFC] = supported_apps[TRANSPORT.NFC] return DeviceInfo( config=DeviceConfig( enabled_applications=enabled_apps, auto_eject_timeout=0, challenge_response_timeout=0, device_flags=0, ), serial=None, version=version, form_factor=FORM_FACTOR.USB_A_KEYCHAIN, supported_applications=supported_apps, is_locked=False, )
def _read_info_otp(conn, key_type, interfaces): otp = None serial = None try: mgmt = ManagementSession(conn) except ApplicationNotAvailableError: otp = YubiOtpSession(conn) # Retry during potential reclaim timeout period (~3s). for _ in range(8): try: if otp is None: try: return mgmt.read_device_info() # Rejected while reclaim except NotSupportedError: otp = YubiOtpSession(conn) serial = otp.get_serial( ) # Rejected if reclaim (or not API_SERIAL_VISIBLE) break except CommandRejectedError: sleep(0.5) # Potential reclaim else: otp = YubiOtpSession(conn) # Synthesize info logger.debug("Unable to get info via Management application, use fallback") version = otp.version if key_type == YUBIKEY.NEO: usb_supported = BASE_NEO_APPS if USB_INTERFACE.FIDO in interfaces or version >= (3, 3, 0): usb_supported |= CAPABILITY.U2F capabilities = { TRANSPORT.USB: usb_supported, TRANSPORT.NFC: usb_supported, } elif key_type == YUBIKEY.YKP: capabilities = { TRANSPORT.USB: CAPABILITY.OTP | TRANSPORT.U2F, } else: capabilities = { TRANSPORT.USB: CAPABILITY.OTP, } return DeviceInfo( config=DeviceConfig( enabled_capabilities={}, # Populated later auto_eject_timeout=0, challenge_response_timeout=0, device_flags=0, ), serial=serial, version=version, form_factor=FORM_FACTOR.UNKNOWN, supported_capabilities=capabilities.copy(), is_locked=False, )
def _read_info_otp(conn, key_type, interfaces): try: mgmt = ManagementSession(conn) return mgmt.read_device_info() except (ApplicationNotAvailableError, NotSupportedError): logger.debug("Unable to get info via Management application, use fallback") # Synthesize info version, serial = _otp_read_data(conn) if key_type == YUBIKEY.NEO: usb_supported = BASE_NEO_APPS if USB_INTERFACE.FIDO in interfaces or version >= (3, 3, 0): usb_supported |= APPLICATION.U2F applications = { TRANSPORT.USB: usb_supported, TRANSPORT.NFC: usb_supported, } elif key_type == YUBIKEY.YKP: applications = { TRANSPORT.USB: APPLICATION.OTP | TRANSPORT.U2F, } else: applications = { TRANSPORT.USB: APPLICATION.OTP, } return DeviceInfo( config=DeviceConfig( enabled_applications=applications.copy(), auto_eject_timeout=0, challenge_response_timeout=0, device_flags=0, ), serial=serial, version=version, form_factor=FORM_FACTOR.UNKNOWN, supported_applications=applications.copy(), is_locked=False, )
def _read_info_ccid(conn, key_type, interfaces): try: mgmt = ManagementSession(conn) version = mgmt.version try: return mgmt.read_device_info() except NotSupportedError: # Workaround to "de-select" the Management Applet needed for NEO conn.send_and_receive(b"\xa4\x04\x00\x08") except ApplicationNotAvailableError: logger.debug("Unable to select Management application, use fallback.") version = None # Synthesize data capabilities = CAPABILITY(0) # Try to read serial (and version if needed) from OTP application try: otp_version, serial = _otp_read_data(conn) capabilities |= CAPABILITY.OTP if version is None: version = otp_version except ApplicationNotAvailableError: logger.debug("Unable to select OTP application") serial = None if version is None: version = (3, 0, 0) # Guess, no way to know # Scan for remaining capabilities protocol = SmartCardProtocol(conn) for aid, code in SCAN_APPLETS.items(): try: logger.debug("Check for %s", code) protocol.select(aid) capabilities |= code logger.debug("Found applet: aid: %s, capability: %s", aid, code) except ApplicationNotAvailableError: logger.debug("Missing applet: aid: %s, capability: %s", aid, code) except Exception as e: logger.error( "Error selecting aid: %s, capability: %s", aid, code, exc_info=e, ) # Assume U2F on devices >= 3.3.0 if USB_INTERFACE.FIDO in interfaces or version >= (3, 3, 0): capabilities |= CAPABILITY.U2F return DeviceInfo( config=DeviceConfig( enabled_capabilities={}, # Populated later auto_eject_timeout=0, challenge_response_timeout=0, device_flags=0, ), serial=serial, version=version, form_factor=FORM_FACTOR.UNKNOWN, supported_capabilities={ TRANSPORT.USB: capabilities, TRANSPORT.NFC: capabilities, }, is_locked=False, )