Пример #1
0
    def test_parse_uri_issuer(self):
        no_issuer = CredentialData.parse_uri("otpauth://totp/account"
                                             "?secret=abba")
        self.assertIsNone(no_issuer.issuer)

        from_param = CredentialData.parse_uri("otpauth://totp/account"
                                              "?secret=abba&issuer=Test")
        self.assertEqual("Test", from_param.issuer)

        from_name = CredentialData.parse_uri("otpauth://totp/Test:account"
                                             "?secret=abba")
        self.assertEqual("Test", from_name.issuer)

        with_both = CredentialData.parse_uri("otpauth://totp/TestA:account"
                                             "?secret=abba&issuer=TestB")
        self.assertEqual("TestB", with_both.issuer)
Пример #2
0
def uri(ctx, uri, touch, force):
    """
    Add a new credential from URI.

    Use a URI to add a new credential to your YubiKey.
    """

    if not uri:
        while True:
            uri = click_prompt("Enter an OATH URI")
            try:
                uri = CredentialData.parse_uri(uri)
                break
            except Exception as e:
                click.echo(e)

    ensure_validated(ctx)
    data = uri

    # Steam is a special case where we allow the otpauth
    # URI to contain a 'digits' value of '5'.
    if data.digits == 5 and is_steam(data):
        data.digits = 6

    _add_cred(ctx, data, touch, force)
Пример #3
0
    def test_vector(self, session, params, digits):
        key, values = params

        cred = session.put_credential(
            CredentialData("test", OATH_TYPE.HOTP, HASH_ALGORITHM.SHA1, key, digits)
        )
        for expected in values:
            code = session.calculate_code(cred)
            assert len(code.value) == digits
            assert expected.endswith(code.value)
Пример #4
0
 def test_vector(self, session, params):
     key, challenge, hash_algorithm, expected = params
     if hash_algorithm == HASH_ALGORITHM.SHA512:
         if session.version < (4, 3, 1) or is_fips_version(session.version):
             pytest.skip("SHA512 requires (non-FIPS) YubiKey 4.3.1 or later")
     cred = session.put_credential(
         CredentialData("test", OATH_TYPE.TOTP, hash_algorithm, key)
     )
     value = session.calculate(cred.id, challenge)
     assert value == expected
Пример #5
0
 def ccid_add_credential(
     self,
     name,
     secret,
     issuer,
     oath_type,
     algo,
     digits,
     period,
     touch,
     overwrite=False,
 ):
     secret = parse_b32_key(secret)
     with self._open_oath() as oath_controller:
         try:
             self._unlock(oath_controller)
             cred_data = CredentialData(
                 name,
                 OATH_TYPE[oath_type],
                 HASH_ALGORITHM[algo],
                 secret,
                 int(digits),
                 int(period),
                 0,
                 issuer,
             )
             if not overwrite:
                 key = cred_data.get_id()
                 if key in [
                     cred.id for cred in oath_controller.list_credentials()
                 ]:
                     return failure("credential_already_exists")
             oath_controller.put_credential(cred_data, 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 failure("no_space")
             else:
                 raise
         return success()
Пример #6
0
    def test_vector(self, session, params, digits):
        timestamp, hash_algorithm, value, key = params
        if hash_algorithm == HASH_ALGORITHM.SHA512:
            if session.version < (4, 3, 1) or is_fips_version(session.version):
                pytest.skip("SHA512 requires (non-FIPS) YubiKey 4.3.1 or later")

        cred = session.put_credential(
            CredentialData("test", OATH_TYPE.TOTP, hash_algorithm, key, digits)
        )
        code = session.calculate_code(cred, timestamp)
        assert len(code.value) == digits
        assert value.endswith(code.value)
Пример #7
0
 def test_parse_uri(self):
     data = CredentialData.parse_uri("otpauth://totp/Issuer:account"
                                     "?secret=abba&issuer=Issuer"
                                     "&algorithm=SHA256&digits=7"
                                     "&period=20&counter=5")
     self.assertEqual(b"\0B", data.secret)
     self.assertEqual("Issuer", data.issuer)
     self.assertEqual("account", data.name)
     self.assertEqual(OATH_TYPE.TOTP, data.oath_type)
     self.assertEqual(HASH_ALGORITHM.SHA256, data.hash_algorithm)
     self.assertEqual(7, data.digits)
     self.assertEqual(20, data.period)
     self.assertEqual(5, data.counter)
Пример #8
0
 def parse_qr(self, screenshot):
     data = b64decode(screenshot["data"])
     image = PixelImage(data, screenshot["width"], screenshot["height"])
     for qr in qrparse.parse_qr_codes(image, 2):
         try:
             return success(
                 credential_data_to_dict(
                     CredentialData.parse_uri(qrdecode.decode_qr_data(qr))
                 )
             )
         except Exception as e:
             logger.error("Failed to parse uri", exc_info=e)
             return failure("failed_to_parse_uri")
     return failure("no_credential_found")
Пример #9
0
def add(
    ctx,
    secret,
    name,
    issuer,
    period,
    oath_type,
    digits,
    touch,
    algorithm,
    counter,
    force,
    password,
    remember,
):
    """
    Add a new account.

    This will add a new OATH account to the YubiKey.

    \b
    NAME    Human readable name of the account, such as a username or e-mail address.
    SECRET  Base32-encoded secret/key value provided by the server.
    """

    digits = int(digits)

    if not secret:
        while True:
            secret = click_prompt("Enter a secret key (base32)")
            try:
                secret = parse_b32_key(secret)
                break
            except Exception as e:
                click.echo(e)

    _init_session(ctx, password, remember)

    _add_cred(
        ctx,
        CredentialData(
            name, oath_type, algorithm, secret, digits, period, counter, issuer
        ),
        touch,
        force,
    )
Пример #10
0
def add(
    ctx,
    secret,
    name,
    issuer,
    period,
    oath_type,
    digits,
    touch,
    algorithm,
    counter,
    force,
    password,
    remember,
):
    """
    Add a new account.

    This will add a new OATH account to the YubiKey.
    """

    digits = int(digits)

    if not secret:
        while True:
            secret = click_prompt("Enter a secret key (base32)")
            try:
                secret = parse_b32_key(secret)
                break
            except Exception as e:
                click.echo(e)

    _init_session(ctx, password, remember)

    _add_cred(
        ctx,
        CredentialData(name, oath_type, algorithm, secret, digits, period,
                       counter, issuer),
        touch,
        force,
    )
Пример #11
0
def add(
    ctx,
    secret,
    name,
    issuer,
    period,
    oath_type,
    digits,
    touch,
    algorithm,
    counter,
    force,
):
    """
    Add a new credential.

    This will add a new credential to your YubiKey.
    """

    digits = int(digits)

    if not secret:
        while True:
            secret = click_prompt("Enter a secret key (base32)")
            try:
                secret = parse_b32_key(secret)
                break
            except Exception as e:
                click.echo(e)

    ensure_validated(ctx)

    _add_cred(
        ctx,
        CredentialData(
            name, oath_type, algorithm, secret, digits, period, counter, issuer
        ),
        touch,
        force,
    )
Пример #12
0
def uri(ctx, data, touch, force, password, remember):
    """
    Add a new account from an otpauth:// URI.

    Use a URI to add a new account to the YubiKey.
    """

    if not data:
        while True:
            uri = click_prompt("Enter an OATH URI")
            try:
                data = CredentialData.parse_uri(uri)
                break
            except Exception as e:
                click.echo(e)

    # Steam is a special case where we allow the otpauth
    # URI to contain a 'digits' value of '5'.
    if data.digits == 5 and is_steam(data):
        data.digits = 6

    _init_session(ctx, password, remember)
    _add_cred(ctx, data, touch, force)
Пример #13
0
def click_parse_uri(ctx, param, val):
    try:
        return CredentialData.parse_uri(val)
    except ValueError:
        raise click.BadParameter("URI seems to have the wrong format.")
Пример #14
0
from ykman.device import is_fips_version
from . import condition


KEY = bytes.fromhex("01020304050607080102030405060708")


@pytest.fixture
@condition.capability(CAPABILITY.OATH)
def session(ccid_connection):
    oath = OathSession(ccid_connection)
    oath.reset()
    yield oath


CRED_DATA = CredentialData("name", OATH_TYPE.TOTP, HASH_ALGORITHM.SHA1, b"secret")


class TestFunctions:
    @condition.min_version(5, 3)
    def test_rename(self, session):
        cred = session.put_credential(CRED_DATA)
        new_id = session.rename_credential(cred.id, "newname", "newissuer")
        with pytest.raises(ApduError):
            session.calculate(cred.id, b"challenge")
        session.calculate(new_id, b"challenge")

    @condition.min_version(5, 3)
    def test_rename_to_existing(self, session):
        cred = session.put_credential(CRED_DATA)
        new_id = session.rename_credential(cred.id, "newname", "newissuer")