Ejemplo 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
Ejemplo n.º 2
0
    def test_get_pin_token(self):
        prot = ClientPin(mock.MagicMock(), PinProtocolV1())
        prot._get_shared_secret = mock.Mock(return_value=({}, SHARED))
        prot.ctap.client_pin.return_value = {2: TOKEN_ENC}

        self.assertEqual(prot.get_pin_token("1234"), TOKEN)
        prot.ctap.client_pin.assert_called_once()
        self.assertEqual(
            prot.ctap.client_pin.call_args[1]["pin_hash_enc"], PIN_HASH_ENC
        )
Ejemplo n.º 3
0
def _init_credman(ctx, pin):
    pin = _require_pin(ctx, pin, "Credential Management")

    ctap2 = ctx.obj.get("ctap2")
    client_pin = ClientPin(ctap2)
    try:
        token = client_pin.get_pin_token(pin, ClientPin.PERMISSION.CREDENTIAL_MGMT)
    except CtapError as e:
        logger.error("Ctap error", exc_info=e)
        _fail_pin_error(ctx, e, "PIN error: %s")

    return CredentialManagement(ctap2, client_pin.protocol, token)
Ejemplo n.º 4
0
def _init_bio(ctx, pin):
    ctap2 = ctx.obj.get("ctap2")
    if not ctap2 or "bioEnroll" not in ctap2.info.options:
        cli_fail("Biometrics is not supported on this YubiKey.")
    pin = _require_pin(ctx, pin, "Biometrics")

    client_pin = ClientPin(ctap2)
    try:
        token = client_pin.get_pin_token(pin, ClientPin.PERMISSION.BIO_ENROLL)
    except CtapError as e:
        logger.error("Ctap error", exc_info=e)
        _fail_pin_error(ctx, e, "PIN error: %s")

    return FPBioEnrollment(ctap2, client_pin.protocol, token)
Ejemplo n.º 5
0
def verify(ctx, pin):
    """
    Verify the FIDO PIN against a YubiKey.

    For YubiKeys supporting FIDO2 this will reset the "retries" counter of the PIN.
    For YubiKey FIPS this will unlock the session, allowing U2F registration.
    """

    ctap2 = ctx.obj.get("ctap2")
    if ctap2:
        pin = _require_pin(ctx, pin)
        client_pin = ClientPin(ctap2)
        try:
            # Get a PIN token to verify the PIN.
            client_pin.get_pin_token(
                pin, ClientPin.PERMISSION.GET_ASSERTION, "ykman.example.com"
            )
        except CtapError as e:
            logger.error("PIN verification failed", exc_info=e)
            cli_fail(f"Error: {e}")
    elif is_fips_version(ctx.obj["info"].version):
        _fail_if_not_valid_pin(ctx, pin, True)
        try:
            fips_verify_pin(ctx.obj["conn"], pin)
        except ApduError as e:
            logger.error("PIN verification failed", exc_info=e)
            if e.code == SW.VERIFY_FAIL_NO_RETRY:
                cli_fail("Wrong PIN.")
            elif e.code == SW.AUTH_METHOD_BLOCKED:
                cli_fail("PIN is blocked.")
            elif e.code == SW.COMMAND_NOT_ALLOWED:
                cli_fail("PIN is not set.")
            else:
                cli_fail(f"PIN verification failed: {e.code.name}")
    else:
        cli_fail("This YubiKey does not support a FIDO PIN.")
    click.echo("PIN verified.")
Ejemplo n.º 6
0
def _init_bio(ctx, pin):
    ctap2 = ctx.obj.get("ctap2")

    if not ctap2 or "bioEnroll" not in ctap2.info.options:
        cli_fail("Biometrics is not supported on this YubiKey.")
    elif not ctap2.info.options.get("clientPin"):
        cli_fail("Biometrics requires having a PIN. Set a PIN first.")

    if pin is None:
        pin = _prompt_current_pin(prompt="Enter your PIN")

    client_pin = ClientPin(ctap2)
    try:
        token = client_pin.get_pin_token(pin, ClientPin.PERMISSION.BIO_ENROLL)
    except CtapError as e:
        logger.error("Ctap error", exc_info=e)
        _fail_pin_error(ctx, e, "PIN error: %s")

    return FPBioEnrollment(ctap2, client_pin.protocol, token)
Ejemplo n.º 7
0
def _init_credman(ctx, pin):
    ctap2 = ctx.obj.get("ctap2")

    if not ctap2:
        cli_fail("Credential management not supported on this YubiKey.")
    elif not ctap2.info.options.get("clientPin"):
        cli_fail("Credential management requires having a PIN. Set a PIN first.")

    if pin is None:
        pin = _prompt_current_pin(prompt="Enter your PIN")

    client_pin = ClientPin(ctap2)
    try:
        token = client_pin.get_pin_token(pin, ClientPin.PERMISSION.CREDENTIAL_MGMT)
    except CtapError as e:
        logger.error("Ctap error", exc_info=e)
        _fail_pin_error(ctx, e, "PIN error: %s")

    return CredentialManagement(ctap2, client_pin.protocol, token)
Ejemplo n.º 8
0
            break
    except Exception:  # nosec
        continue
else:
    print("No Authenticator supporting bioEnroll found")
    sys.exit(1)

if not ctap.info.options.get("clientPin"):
    print("PIN not set for the device!")
    sys.exit(1)

# Authenticate with PIN
print("Preparing to enroll a new fingerprint.")
pin = getpass("Please enter PIN: ")
client_pin = ClientPin(ctap)
pin_token = client_pin.get_pin_token(pin, ClientPin.PERMISSION.BIO_ENROLL)
bio = FPBioEnrollment(ctap, client_pin.protocol, pin_token)

print(bio.enumerate_enrollments())

# Start enrollment
enroller = bio.enroll()
template_id = None
while template_id is None:
    print("Press your fingerprint against the sensor now...")
    try:
        template_id = enroller.capture()
        print(enroller.remaining, "more scans needed.")
    except CaptureError as e:
        print(e)
print("Fingerprint registered successfully with ID:", template_id)
Ejemplo n.º 9
0
print("\nTouch your authenticator device now...\n")

result = client.make_credential(options, pin=pin)
key = result.attestation_object.large_blob_key

# Complete registration
auth_data = server.register_complete(state, result.client_data,
                                     result.attestation_object)
credentials = [auth_data.credential_data]

print("New credential created!")
print("Large Blob Key:", key)

client_pin = ClientPin(client.ctap2)
if pin:
    token = client_pin.get_pin_token(pin,
                                     ClientPin.PERMISSION.LARGE_BLOB_WRITE)
else:
    token = client_pin.get_uv_token(ClientPin.PERMISSION.LARGE_BLOB_WRITE)
large_blobs = LargeBlobs(client.ctap2, client_pin.protocol, token)

# Write a large blob
print("Writing a large blob...")
large_blobs.put_blob(key, b"Here is some data to store!")

# Prepare parameters for getAssertion
request_options, state = server.authenticate_begin(user_verification=uv)

# Enable largeBlobKey
options = request_options["publicKey"]
options.extensions = {"largeBlobKey": True}