Exemplo n.º 1
0
def oath(ctx, password):
    """
    Manage OATH Application.

    Examples:

    \b
      Generate codes for credentials starting with 'yubi':
      $ ykman oath code yubi

    \b
      Add a touch credential with the secret key f5up4ub3dw and the name yubico:
      $ ykman oath add yubico f5up4ub3dw --touch

    \b
      Set a password for the OATH application:
      $ ykman oath set-password
    """
    try:
        controller = OathSession(ctx.obj["conn"])
        ctx.obj["controller"] = controller
        ctx.obj["settings"] = Settings("oath")
    except ApduError as e:
        if e.sw == SW.FILE_NOT_FOUND:
            ctx.fail("The OATH application can't be found on this YubiKey.")
        raise

    if password:
        ctx.obj["key"] = controller.derive_key(password)
Exemplo n.º 2
0
def get_unlocked_session(device_info: Optional[tuple[YkmanDevice,
                                                     DeviceInfo]] = None,
                         password: Optional[str] = None) -> OathSession:
    if device_info is None:
        device_info = get_device()
    if device_info is None:
        raise UndefinedDevice

    device, info = device_info
    connection = device.open_connection(SmartCardConnection)
    session = OathSession(connection=connection)
    if not session.locked:
        return session

    if not password:
        password = get_password(info)
    if not password:
        try:
            password = prompt(f"Password for YubiKey '{info.serial}'",
                              hide_input=True,
                              type=str,
                              err=True)
        except Abort:
            raise UndefinedPasswordError

    try:
        key = session.derive_key(password=password)
        session.validate(key=key)
    except Exception:
        raise WrongPasswordError

    return session
Exemplo n.º 3
0
def validate(
        password: str,
        session: OathSession = None,
        device_info: Optional[tuple[YkmanDevice, DeviceInfo]] = None) -> None:
    if session is None:
        session = get_session(device_info)

    key = session.derive_key(password)
    try:
        session.validate(key)
        return
    except Exception:
        raise WrongPasswordError
Exemplo n.º 4
0
def oath_info(conn):
    try:
        oath = OathSession(conn)
        return [
            "\tOATH",
            f"\t\tOath version: {'.'.join('%d' % d for d in oath.version)}",
            f"\t\tPassword protected: {oath.locked}",
        ]
    except Exception as e:
        return [f"\tOATH not accessible {e}"]
Exemplo n.º 5
0
def get_session(
    device_info: Optional[tuple[YkmanDevice, DeviceInfo]] = None
) -> Optional[OathSession]:
    if not device_info:
        device_info = get_device()
    if not device_info:
        return None

    device, _ = device_info
    connection = device.open_connection(SmartCardConnection)
    return OathSession(connection=connection)
Exemplo n.º 6
0
def oath(ctx):
    """
    Manage the OATH application.

    Examples:

    \b
      Generate codes for accounts starting with 'yubi':
      $ ykman oath accounts code yubi

    \b
      Add an account with the secret key f5up4ub3dw and the name yubico,
      which requires touch:
      $ ykman oath accounts add yubico f5up4ub3dw --touch

    \b
      Set a password for the OATH application:
      $ ykman oath access change-password
    """
    session = OathSession(ctx.obj["conn"])
    ctx.obj["session"] = session
    ctx.obj["settings"] = AppData("oath")
Exemplo n.º 7
0
 def _get_devices(self, otp_mode=False):
     res = []
     for dev, info in list_all_devices():
         usb_enabled = info.config.enabled_capabilities[TRANSPORT.USB]
         interfaces_enabled = []
         if CAPABILITY.OTP & usb_enabled:
             interfaces_enabled.append("OTP")
         if (CAPABILITY.U2F | CAPABILITY.FIDO2) & usb_enabled:
             interfaces_enabled.append("FIDO")
         if (
             CAPABILITY.OATH | CAPABILITY.PIV | CAPABILITY.OPENPGP
         ) & usb_enabled:
             interfaces_enabled.append("CCID")
         if otp_mode:
             selectable = "OTP" in interfaces_enabled
             has_password = False
         else:
             selectable = "CCID" in interfaces_enabled
             if selectable:
                 with connect_to_device(info.serial, [SmartCardConnection])[
                     0
                 ] as conn:
                     oath = OathSession(conn)
                     has_password = oath.locked
             else:
                 has_password = False
         res.append(
             {
                 "name": get_name(info, dev.pid.get_type()),
                 "version": ".".join(str(d) for d in info.version),
                 "serial": info.serial or "",
                 "usbInterfacesEnabled": interfaces_enabled,
                 "hasPassword": has_password,
                 "selectable": selectable,
                 "validated": not has_password,
             }
         )
     return res
Exemplo n.º 8
0
def get_overall_fips_status(pid, info):
    statuses = {}

    usb_enabled = info.config.enabled_capabilities[TRANSPORT.USB]

    statuses["OTP"] = False
    if usb_enabled & CAPABILITY.OTP:
        with connect_to_device(info.serial, [OtpConnection])[0] as conn:
            otp_app = YubiOtpSession(conn)
            statuses["OTP"] = otp_in_fips_mode(otp_app)

    statuses["OATH"] = False
    if usb_enabled & CAPABILITY.OATH:
        with connect_to_device(info.serial, [SmartCardConnection])[0] as conn:
            oath_app = OathSession(conn)
            statuses["OATH"] = oath_in_fips_mode(oath_app)

    statuses["FIDO U2F"] = False
    if usb_enabled & CAPABILITY.U2F:
        with connect_to_device(info.serial, [FidoConnection])[0] as conn:
            statuses["FIDO U2F"] = ctap_in_fips_mode(conn)

    return statuses
Exemplo n.º 9
0
def get_overall_fips_status(pid, info):
    statuses = {}

    usb_enabled = info.config.enabled_applications[TRANSPORT.USB]

    statuses["OTP"] = False
    if usb_enabled & APPLICATION.OTP:
        for dev in list_otp_devices():
            if dev.pid == pid:
                with dev.open_connection(OtpConnection) as conn:
                    app = YubiOtpSession(conn)
                    if app.get_serial() == info.serial:
                        statuses["OTP"] = otp_in_fips_mode(app)
                        break

    statuses["OATH"] = False
    if usb_enabled & APPLICATION.OATH:
        for dev in list_ccid():
            with dev.open_connection(SmartCardConnection) as conn:
                info2 = read_info(pid, conn)
                if info2.serial == info.serial:
                    app = OathSession(conn)
                    statuses["OATH"] = oath_in_fips_mode(app)
                    break

    statuses["FIDO U2F"] = False
    if usb_enabled & APPLICATION.U2F:
        for dev in list_ctap_devices():
            if dev.pid == pid:
                with dev.open_connection(FidoConnection) as conn:
                    info2 = read_info(pid, conn)
                    if info2.serial == info.serial:
                        statuses["FIDO U2F"] = ctap_in_fips_mode(conn)
                        break

    return statuses
Exemplo n.º 10
0
 def __init__(self, state):
     super().__init__(state)
     self._oath = OathSession(
         connect_to_device(state["yubikey"], [SmartCardConnection])[0])
Exemplo n.º 11
0
class Man(Room):
    """
    The robed man notices you and looks up. His eyes light up and he smiles broadly.

    "Welcome, stranger! I've been alone for so long...".

    He pauses, and in the flash of an instant his smile is replaced with a stern look.
    """
    def __init__(self, state):
        super().__init__(state)
        self._oath = OathSession(
            connect_to_device(state["yubikey"], [SmartCardConnection])[0])

    def go(self, where):
        if where in ("back", "cave", "away"):
            return Cave(self._state)
        return super().go(where)

    def get_description(self):
        output(super().get_description())

        if self._oath.locked:
            output()
            output(
                '"Ah, but, I cannot share with you my secrets unless you can give me '
                'the password. I swore an oath!".')
            output()
            output(
                "His harsh demeanor drops slightly, as he looks at you with a glint "
                "of hope in his eyes. He looks at you expectantly as he continues:"
            )
            output()
            output(
                '"You DO know the password, do you not? Tell me, what is it?".'
            )

            password = input("\n> ")
            output()
            key = self._oath.derive_key(password)
            try:
                self._oath.validate(key)
                output(
                    "The smile returns. "
                    '"I knew it! Welcome, friend, let me share with you my secrets!".'
                )
            except Exception:
                output(
                    "The man looks at you with great dissapointment in his eyes."
                )
                return '"No, no, no... That isn\'t it. Go away! Leave me be!"'

        creds = {k.id: k for k in self._oath.calculate_all()}

        output("He pulls out an old tattered scroll and unravels it.")
        output()
        output(
            '"Which secret shall I share?", he asks, as he extends a bony arm '
            "toward you, beckoning you to read.")
        output()

        if not creds:
            output(
                "You look at the scroll, but it is empty. The man notices your "
                "confusion, and looks at the blank page himself.")
            output()
            output(
                "\"I... I don't understand. There are no secrets here. Surely you must "
                'have secrets to keep?!?".')
            output()
            return (
                "The man is noticably upset, and you deem it wise to not disturb him "
                "further.")
        else:
            for cred_id in creds:
                print(cred_id.decode())

            selected = input("\n> ").encode()
            while selected not in creds:
                output('"What? I don\'t understand you. Speak up!"')
                output()
                output("The man looks at you, expectantly.")
                output()
                selected = input("\n> ").encode()

            cred = creds[selected]
            output()
            output("Ahhh, of course! I knew you would choose that one!")
            output()

            if cred.touch_required:
                output(
                    '"In that case, there\'s just one more thing I must ask of you..." '
                )
                output()
                output(
                    "As he speaks he reaches into his pocket, grasping for something. "
                )
                output(
                    "As he pulls his hand back out you see a glimmer, something small "
                    "and metallic is clenched in his fist. ")
                output(
                    "He slowly opens his hand for you to see a golden ring laying "
                    "across his palm.")
                output()
                output('"Are you ready?", he asks.')

                if input("\n> ").lower() in ("yes", "y"):
                    output()
                    output(
                        "Without a word, the golden ring starts to pulse with a bright "
                        "green glow. ")
                    output(
                        "You feel compelled to reach out and touch it with your finger."
                    )
                    output()

                    try:
                        code = self._oath.calculate_code(cred)
                        output(
                            "As soon as you touch the gold ring it immediately stops "
                            "pulsing. The man pulls it close to his eyes, as if "
                            "struggling to read an inscription. Strange, you think to "
                            "yourself, you could have sworn there was nothing there a "
                            "moment ago.")
                    except Exception:
                        output("The man looks at you disapprovingly.")
                        output()
                        return (
                            '"Those who are to cowardly to act, will never amount to '
                            'anything.", he mutters as he puts the ring back into his '
                            "pocket.")
                else:
                    return "Then go away!"
            else:
                output(
                    "The man reaches into his pocket, grasping for something."
                    "As he pulls his hand back out you see a glimmer, something small"
                    "and metallic is clenched in his fist.")
                output()
                output(
                    "He slowly opens his hand for you to see a golden ring laying"
                    "across his palm. He holds the ring up close to his face, and"
                    "squints, and you realize he is reading an inscription.")
                code = self._oath.calculate_code(cred)

        output("The man reads the inscription out loud:")
        output()

        return format_oath(code.value)
Exemplo n.º 12
0
def session(ccid_connection):
    oath = OathSession(ccid_connection)
    oath.reset()
    yield oath
Exemplo n.º 13
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:
                    with dev.open_connection(SmartCardConnection) as conn:
                        info = read_info(dev.pid, conn)
                        try:
                            oath = OathSession(conn)
                            has_password = oath.locked
                            selectable = True
                        except ApplicationNotAvailableError:
                            selectable = False
                            has_password = False

                    usb_enabled = info.config.enabled_capabilities[TRANSPORT.USB]
                    interfaces_enabled = []
                    if CAPABILITY.OTP & usb_enabled:
                        interfaces_enabled.append("OTP")
                    if (CAPABILITY.U2F | CAPABILITY.FIDO2) & usb_enabled:
                        interfaces_enabled.append("FIDO")
                    if (
                        CAPABILITY.OATH | CAPABILITY.PIV | CAPABILITY.OPENPGP
                    ) & usb_enabled:
                        interfaces_enabled.append("CCID")

                    self._devices.append(
                        {
                            "name": get_name(
                                info, dev.pid.get_type() if dev.pid else None
                            ),
                            "version": ".".join(str(d) for d in info.version),
                            "serial": info.serial or "",
                            "usbInterfacesEnabled": interfaces_enabled,
                            "hasPassword": has_password,
                            "selectable": selectable,
                            "validated": True,  # not has_password
                        }
                    )
                    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._devs:
                    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})
Exemplo n.º 14
0
 def __enter__(self):
     return OathSession(self._conn)