def _calculate(self, credential, timestamp, password_key):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     if controller.locked and password_key is not None:
         controller.validate(a2b_hex(password_key))
     cred = controller.calculate(credential, timestamp)
     return cred
 def _calculate_all(self, timestamp, password_key):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     if controller.locked and password_key is not None:
         controller.validate(a2b_hex(password_key))
     creds = controller.calculate_all(timestamp)
     creds = [c for c in creds if not c.hidden]
     return creds
Exemple #3
0
 def calculate(self, credential, timestamp):
     try:
         dev = self._descriptor.open_device(TRANSPORT.CCID)
         controller = OathController(dev.driver)
         self._unlock(controller)
     except Exception:
         return None
     code = controller.calculate(cred_from_dict(credential), timestamp)
     return code_to_dict(code)
Exemple #4
0
 def calculate(self, credential, timestamp):
     try:
         dev = self._descriptor.open_device(TRANSPORT.CCID)
         controller = OathController(dev.driver)
         self._unlock(controller)
     except Exception:
         return None
     code = controller.calculate(cred_from_dict(credential), timestamp)
     return code_to_dict(code)
 def validate(self, key):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     if key is not None:
         try:
             controller.validate(a2b_hex(key))
             return True
         except:
             return False
Exemple #6
0
 def calculate(self, credential, timestamp, password_key):
     try:
         dev = self._descriptor.open_device(TRANSPORT.CCID)
         controller = OathController(dev.driver)
         if controller.locked and password_key is not None:
             controller.validate(a2b_hex(password_key))
     except:
         return None
     return controller.calculate(Credential.from_dict(credential),
                                 timestamp).to_dict()
Exemple #7
0
 def refresh_credentials(self, timestamp, password_key=None):
     try:
         dev = self._descriptor.open_device(TRANSPORT.CCID)
         controller = OathController(dev.driver)
         if controller.locked and password_key is not None:
             controller.validate(a2b_hex(password_key))
         creds = controller.calculate_all(timestamp)
         return [c.to_dict() for c in creds if not c.is_hidden()]
     except:
         return []
 def refresh_credentials(self, timestamp):
     try:
         dev = self._descriptor.open_device(TRANSPORT.CCID)
         controller = OathController(dev.driver)
         self._unlock(controller)
         entries = controller.calculate_all(timestamp)
         return [pair_to_dict(cred, code) for (cred, code) in entries
                 if not cred.is_hidden]
     except Exception:
         return []
Exemple #9
0
 def refresh_credentials(self, timestamp):
     try:
         dev = self._descriptor.open_device(TRANSPORT.CCID)
         controller = OathController(dev.driver)
         self._unlock(controller)
         entries = controller.calculate_all(timestamp)
         return [pair_to_dict(cred, code) for (cred, code) in entries
                 if not cred.is_hidden]
     except Exception:
         return []
Exemple #10
0
 def provide_password(self, password, remember=False):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     self._key = controller.derive_key(password)
     try:
         controller.validate(self._key)
     except Exception:
         return False
     if remember:
         keys = self.settings.setdefault('keys', {})
         keys[controller.id] = b2a_hex(self._key).decode()
         self.settings.write()
     return True
Exemple #11
0
 def provide_password(self, password, remember=False):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     self._key = controller.derive_key(password)
     try:
         controller.validate(self._key)
     except Exception:
         return False
     if remember:
         keys = self.settings.setdefault('keys', {})
         keys[controller.id] = b2a_hex(self._key).decode()
         self.settings.write()
     return True
 def needs_validation(self):
     try:
         dev = self._descriptor.open_device(TRANSPORT.CCID)
         controller = OathController(dev.driver)
         return controller.locked
     except:
         return False
Exemple #13
0
 def get_oath_id(self):
     try:
         dev = self._descriptor.open_device(TRANSPORT.CCID)
         controller = OathController(dev.driver)
     except:
         return None
     return b2a_hex(controller.id).decode('utf-8')
Exemple #14
0
 def set_password(self, new_password, remember=False):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     self._unlock(controller)
     keys = self.settings.setdefault('keys', {})
     if new_password is not None:
         self._key = controller.set_password(new_password)
         if remember:
             keys[controller.id] = b2a_hex(self._key).decode()
         elif controller.id in keys:
             del keys[controller.id]
     else:
         controller.clear_password()
         del keys[controller.id]
         self._key = None
     self.settings.write()
Exemple #15
0
    def refresh(self, otp_mode=False):
        descriptors = get_descriptors()
        if len(descriptors) != 1:
            self._descriptor = None
            return None

        desc = descriptors[0]
        if desc.fingerprint != (
                self._descriptor.fingerprint if self._descriptor else None) \
                or not otp_mode and not self._dev_info.get('version'):
            try:
                dev = desc.open_device(
                    TRANSPORT.OTP if otp_mode else TRANSPORT.CCID)
                if otp_mode:
                    version = None
                else:
                    controller = OathController(dev.driver)
                    version = controller.version
            except Exception:
                return None
            self._descriptor = desc
            self._dev_info = {
                'name': dev.device_name,
                'version': version,
                'serial': dev.serial or '',
                'enabled': [c.name for c in CAPABILITY if c & dev.enabled],
                'connections':
                [t.name for t in TRANSPORT if t & dev.capabilities]
            }

        return self._dev_info
Exemple #16
0
 def set_password(self, new_password, remember=False):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     self._unlock(controller)
     keys = self.settings.setdefault('keys', {})
     if new_password is not None:
         self._key = controller.set_password(new_password)
         if remember:
             keys[controller.id] = b2a_hex(self._key).decode()
         elif controller.id in keys:
             del keys[controller.id]
     else:
         controller.clear_password()
         del keys[controller.id]
         self._key = None
     self.settings.write()
 def set_password(self, new_password, password_key):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     if controller.locked and password_key is not None:
         controller.validate(a2b_hex(password_key))
     if new_password is not None:
         key = derive_key(controller.id, new_password)
         controller.set_password(key)
     else:
         controller.clear_password()
    def refresh_devices(self, otp_mode=False, reader_filter=None):
        self._devices = []

        if not otp_mode and reader_filter:
            self._reader_filter = reader_filter
            dev = self._get_dev_from_reader()
            if dev:
                if is_nfc(self._reader_filter):
                    selectable = nfc_selectable(dev)
                else:
                    selectable = usb_selectable(dev, otp_mode)
                if selectable:
                    controller = OathController(dev.driver)
                    has_password = controller.locked
                else:
                    has_password = False
                self._devices.append({
                    'name':
                    dev.device_name,
                    'version':
                    '.'.join(str(x)
                             for x in dev.version) if dev.version else '',
                    'serial':
                    dev.serial or '',
                    'usbInterfacesEnabled':
                    str(dev.mode).split('+'),
                    'hasPassword':
                    has_password,
                    'selectable':
                    selectable,
                    'validated':
                    True
                })
                return success({'devices': self._devices})
            else:
                return success({'devices': []})
        else:
            self._reader_filter = None
            # Forget current serial and derived key if no descriptors
            # Return empty list of devices
            if not self._descs:
                self._current_serial = None
                self._current_derived_key = None
                return success({'devices': []})

            self._devices = self._get_devices(otp_mode)

            # If no current serial, or current serial seems removed,
            # select the first serial found.
            if not self._current_serial or (self._current_serial not in [
                    dev['serial'] for dev in self._devices
            ]):
                for dev in self._devices:
                    if dev['serial']:
                        self._current_serial = dev['serial']
                        break
            return success({'devices': self._devices})
Exemple #19
0
 def add_credential(self, name, secret, issuer, oath_type, algo, digits,
                    period, touch):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     self._unlock(controller)
     try:
         secret = parse_b32_key(secret)
     except Exception as e:
         return str(e)
     try:
         controller.put(
             CredentialData(secret, issuer, name, OATH_TYPE[oath_type],
                            ALGO[algo], int(digits), int(period), 0, touch))
     except APDUError as e:
         # NEO doesn't return a no space error if full,
         # but a command aborted error. Assume it's because of
         # no space in this context.
         if e.sw in (SW.NO_SPACE, SW.COMMAND_ABORTED):
             return 'No space'
         else:
             raise
Exemple #20
0
        def refresh_devices(self, otp_mode=False, reader_filter=None):
            self._devices = []

            if not otp_mode and reader_filter:
                self._reader_filter = reader_filter
                dev = self._get_dev_from_reader()
                if dev:
                    if is_nfc(self._reader_filter):
                        selectable = nfc_selectable(dev)
                    else:
                        selectable = usb_selectable(dev, otp_mode)
                    if selectable:
                        controller = OathController(dev.driver)
                        has_password = controller.locked
                    else:
                        has_password = False
                    self._devices.append(
                        {
                            "name": dev.device_name,
                            "version": ".".join(str(x) for x in dev.version)
                            if dev.version
                            else "",
                            "serial": dev.serial or "",
                            "usbInterfacesEnabled": str(dev.mode).split("+"),
                            "hasPassword": has_password,
                            "selectable": selectable,
                            "validated": True,
                        }
                    )
                    return success({"devices": self._devices})
                else:
                    return success({"devices": []})
            else:
                self._reader_filter = None
                # Forget current serial and derived key if no descriptors
                # Return empty list of devices
                if not self._descs:
                    self._current_serial = None
                    self._current_derived_key = None
                    return success({"devices": []})

                self._devices = self._get_devices(otp_mode)

                # If no current serial, or current serial seems removed,
                # select the first serial found.
                if not self._current_serial or (
                    self._current_serial not in [dev["serial"] for dev in self._devices]
                ):
                    for dev in self._devices:
                        if dev["serial"]:
                            self._current_serial = dev["serial"]
                            break
                return success({"devices": self._devices})
Exemple #21
0
    def refresh(self, otp_mode=False):
        descriptors = get_descriptors()
        if len(descriptors) != 1:
            self._descriptor = None
            return None

        desc = descriptors[0]

        unmatched_otp_mode = otp_mode and not desc.mode.has_transport(
            TRANSPORT.OTP)
        unmatched_ccid_mode = not otp_mode and not desc.mode.has_transport(
            TRANSPORT.CCID)

        if unmatched_otp_mode or unmatched_ccid_mode:
            return {
                'transports':
                [t.name for t in TRANSPORT.split(desc.mode.transports)],
                'usable':
                False,
            }

        if desc.fingerprint != (
                self._descriptor.fingerprint if self._descriptor else None) \
                or not otp_mode and not self._dev_info.get('version'):
            try:
                dev = desc.open_device(
                    TRANSPORT.OTP if otp_mode else TRANSPORT.CCID)
                if otp_mode:
                    version = None
                else:
                    controller = OathController(dev.driver)
                    version = controller.version
            except Exception as e:
                logger.debug('Failed to refresh YubiKey', exc_info=e)
                return None

            self._descriptor = desc
            self._dev_info = {
                'usable':
                True,
                'name':
                dev.device_name,
                'version':
                version,
                'serial':
                dev.serial or '',
                'usb_interfaces_supported':
                [t.name for t in TRANSPORT if t & dev.config.usb_supported],
                'usb_interfaces_enabled':
                str(dev.mode).split('+')
            }

        return self._dev_info
 def add_credential(self, name, key, oath_type, digits, algo, touch,
                    password_key):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     if controller.locked and password_key is not None:
         controller.validate(a2b_hex(password_key))
     try:
         key = parse_b32_key(key)
     except Exception as e:
         return str(e)
     try:
         controller.put(key,
                        name,
                        oath_type,
                        digits,
                        algo=algo,
                        require_touch=touch)
     except APDUError as e:
         # NEO doesn't return a no space error if full,
         # but a command aborted error. Assume it's because of
         # no space in this context.
         if e.sw == SW.NO_SPACE or e.sw == SW.COMMAND_ABORTED:
             return 'No space'
         else:
             raise
Exemple #23
0
 def add_credential(
         self, name, secret, issuer, oath_type, algo, digits,
         period, touch):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     self._unlock(controller)
     try:
         secret = parse_b32_key(secret)
     except Exception as e:
         return str(e)
     try:
         controller.put(CredentialData(
             secret, issuer, name, OATH_TYPE[oath_type], ALGO[algo],
             int(digits), int(period), 0, touch
         ))
     except APDUError as e:
         # NEO doesn't return a no space error if full,
         # but a command aborted error. Assume it's because of
         # no space in this context.
         if e.sw in (SW.NO_SPACE, SW.COMMAND_ABORTED):
             return 'No space'
         else:
             raise
Exemple #24
0
    def _get_devices(self, otp_mode=False):
        res = []
        descs_to_match = self._descs[:]
        handled_serials = set()
        time.sleep(0.5)  # Let macOS take time to see the reader
        for transport in [TRANSPORT.CCID, TRANSPORT.OTP, TRANSPORT.FIDO]:
            if not descs_to_match:
                return res
            for dev in list_devices(transport):
                if not descs_to_match:
                    return res

                serial = dev.serial
                selectable = usb_selectable(dev, otp_mode)

                if selectable and not otp_mode and transport == TRANSPORT.CCID:
                    controller = OathController(dev.driver)
                    has_password = controller.locked
                else:
                    has_password = False

                if serial not in handled_serials:
                    handled_serials.add(serial)
                    matches = [
                        d for d in descs_to_match
                        if (d.key_type, d.mode) == (dev.driver.key_type,
                                                    dev.driver.mode)
                    ]
                    if len(matches) > 0:
                        matching_descriptor = matches[0]
                        res.append({
                            'name':
                            dev.device_name,
                            'version':
                            '.'.join(
                                str(x)
                                for x in dev.version) if dev.version else '',
                            'serial':
                            serial or '',
                            'usbInterfacesEnabled':
                            str(dev.mode).split('+'),
                            'hasPassword':
                            has_password,
                            'selectable':
                            selectable,
                            'validated':
                            not has_password
                        })
                        descs_to_match.remove(matching_descriptor)
        return res
 def add_credential(self, name, key, oath_type, digits, algo, touch,
                    password_key):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     if controller.locked and password_key is not None:
         controller.validate(a2b_hex(password_key))
     try:
         key = parse_b32_key(key)
     except Exception as e:
         return str(e)
     controller.put(key,
                    name,
                    oath_type,
                    digits,
                    algo=algo,
                    require_touch=touch)
 def derive_key(self, password):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     key = derive_key(controller.id, password)
     return b2a_hex(key).decode('utf-8')
Exemple #27
0
 def reset(self):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     controller.reset()
Exemple #28
0
 def delete_credential(self, credential):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     self._unlock(controller)
     controller.delete(cred_from_dict(credential))
 def delete_credential(self, credential, password_key):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     if controller.locked and password_key is not None:
         controller.validate(a2b_hex(password_key))
     controller.delete(Credential.from_dict(credential))
Exemple #30
0
        def _get_devices(self, otp_mode=False):
            res = []
            descs_to_match = self._descs[:]
            handled_serials = set()
            time.sleep(0.5)  # Let macOS take time to see the reader
            for transport in [TRANSPORT.CCID, TRANSPORT.OTP, TRANSPORT.FIDO]:
                if not descs_to_match:
                    return res
                for dev in list_devices(transport):
                    if not descs_to_match:
                        return res

                    serial = dev.serial
                    selectable = usb_selectable(dev, otp_mode)

                    if dev.version:
                        version = ".".join(str(x) for x in dev.version)
                    else:
                        version = ""

                    if selectable and not otp_mode and transport == TRANSPORT.CCID:
                        controller = OathController(dev.driver)
                        has_password = controller.locked
                    else:
                        has_password = False

                    if serial not in handled_serials:
                        handled_serials.add(serial)

                        matches_all = [
                            d
                            for d in self._descs[:]
                            if (d.key_type, d.mode)
                            == (dev.driver.key_type, dev.driver.mode)
                        ]

                        matches_left = [
                            d
                            for d in descs_to_match
                            if (d.key_type, d.mode)
                            == (dev.driver.key_type, dev.driver.mode)
                        ]

                        if len(matches_left) > 0:

                            if len(matches_all) == 1 and version == "":
                                # Only one matching descriptor of all descriptors,
                                # try reading any missing version from it
                                descriptor = matches_all[0]
                                if descriptor.version:
                                    version = ".".join(
                                        str(x) for x in descriptor.version
                                    )

                            res.append(
                                {
                                    "name": dev.device_name,
                                    "version": version,
                                    "serial": serial or "",
                                    "usbInterfacesEnabled": str(dev.mode).split("+"),
                                    "hasPassword": has_password,
                                    "selectable": selectable,
                                    "validated": not has_password,
                                }
                            )

                            descs_to_match.remove(matches_left[0])
            return res
Exemple #31
0
 def get_oath_id(self):
     try:
         dev = self._descriptor.open_device(TRANSPORT.CCID)
         return OathController(dev.driver).id
     except Exception:
         return None
Exemple #32
0
 def needs_validation(self):
     try:
         dev = self._descriptor.open_device(TRANSPORT.CCID)
         return not self._unlock(OathController(dev.driver))
     except Exception:
         return True
Exemple #33
0
 def delete_credential(self, credential):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     self._unlock(controller)
     controller.delete(cred_from_dict(credential))
 def __enter__(self):
     return OathController(self._dev.driver)
Exemple #35
0
 def reset(self):
     dev = self._descriptor.open_device(TRANSPORT.CCID)
     controller = OathController(dev.driver)
     controller.reset()