Esempio n. 1
0
class Fido2Controller(object):
    def __init__(self, ctap_device):
        self.ctap = CTAP2(ctap_device)
        self.pin = ClientPin(self.ctap)
        self._info = self.ctap.get_info()
        self._pin = self._info.options["clientPin"]

    @property
    def has_pin(self):
        return self._pin

    def get_resident_credentials(self, pin):
        _credman = CredentialManagement(
            self.ctap,
            self.pin.protocol,
            self.pin.get_pin_token(pin, ClientPin.PERMISSION.CREDENTIAL_MGMT),
        )

        for rp in _credman.enumerate_rps():
            for cred in _credman.enumerate_creds(
                    rp[CredentialManagement.RESULT.RP_ID_HASH]):
                yield ResidentCredential(cred, rp)

    def delete_resident_credential(self, credential_id, pin):
        _credman = CredentialManagement(
            self.ctap,
            self.pin.protocol,
            self.pin.get_pin_token(pin, ClientPin.PERMISSION.CREDENTIAL_MGMT),
        )

        for cred in self.get_resident_credentials(pin):
            if credential_id == cred.credential_id:
                _credman.delete_cred(credential_id)

    def get_pin_retries(self):
        return self.pin.get_pin_retries()

    def set_pin(self, pin):
        self.pin.set_pin(pin)
        self._pin = True

    def change_pin(self, old_pin, new_pin):
        self.pin.change_pin(old_pin, new_pin)

    def reset(self, touch_callback=None):
        if touch_callback:
            touch_timer = Timer(0.500, touch_callback)
            touch_timer.start()
        try:
            self.ctap.reset()
            self._pin = False
        finally:
            if touch_callback:
                touch_timer.cancel()

    @property
    def is_fips(self):
        return False
Esempio n. 2
0
def info(ctx):
    """
    Display general status of the FIDO2 application.
    """
    conn = ctx.obj["conn"]
    ctap2 = ctx.obj.get("ctap2")

    if is_fips_version(ctx.obj["info"].version):
        click.echo("FIPS Approved Mode: " + ("Yes" if is_in_fips_mode(conn) else "No"))
    elif ctap2:
        client_pin = ClientPin(ctap2)  # N.B. All YubiKeys with CTAP2 support PIN.
        if ctap2.info.options["clientPin"]:
            if ctap2.info.force_pin_change:
                click.echo(
                    "NOTE: The FIDO PID is disabled and must be changed before it can "
                    "be used!"
                )
            pin_retries, power_cycle = client_pin.get_pin_retries()
            if pin_retries:
                click.echo(f"PIN is set, with {pin_retries} attempt(s) remaining.")
                if power_cycle:
                    click.echo(
                        "PIN is temporarily blocked. "
                        "Remove and re-insert the YubiKey to unblock."
                    )
            else:
                click.echo("PIN is set, but has been blocked.")
        else:
            click.echo("PIN is not set.")

        bio_enroll = ctap2.info.options.get("bioEnroll")
        if bio_enroll:
            uv_retries, _ = client_pin.get_uv_retries()
            if uv_retries:
                click.echo(
                    f"Fingerprints registered, with {uv_retries} attempt(s) "
                    "remaining."
                )
            else:
                click.echo(
                    "Fingerprints registered, but blocked until PIN is verified."
                )
        elif bio_enroll is False:
            click.echo("No fingerprints have been registered.")

        always_uv = ctap2.info.options.get("alwaysUv")
        if always_uv is not None:
            click.echo(
                "Always Require User Verification is turned "
                + ("on." if always_uv else "off.")
            )

    else:
        click.echo("PIN is not supported.")
Esempio n. 3
0
 def fido_pin_retries(self):
     try:
         with self._open_device([FidoConnection]) as conn:
             ctap2 = Ctap2(conn)
             client_pin = ClientPin(ctap2)
             return success({'retries': client_pin.get_pin_retries()[0]})
     except CtapError as e:
         if e.code == CtapError.ERR.PIN_AUTH_BLOCKED:
             return failure('PIN authentication is currently blocked. '
                            'Remove and re-insert the YubiKey.')
         if e.code == CtapError.ERR.PIN_BLOCKED:
             return failure('PIN is blocked.')
         raise