def test_modhex_decode(self): self.assertEqual(b"", modhex_decode("")) self.assertEqual(b"\x2d\x34\x4e\x83", modhex_decode("dteffuje")) self.assertEqual( b"\x69\xb6\x48\x1c\x8b\xab\xa2\xb6\x0e\x8f\x22\x17\x9b\x58\xcd\x56", modhex_decode("hknhfjbrjnlnldnhcujvddbikngjrtgh"), )
def program_otp(self, slot, public_id, private_id, key, upload=False, app_version='unknown'): key = a2b_hex(key) public_id = modhex_decode(public_id) private_id = a2b_hex(private_id) upload_url = None with self._open_device([OtpConnection]) as conn: if upload: try: upload_url = prepare_upload_key( key, public_id, private_id, serial=self._dev_info['serial'], user_agent='ykman-qt/' + app_version) except PrepareUploadFailed as e: logger.debug('YubiCloud upload failed', exc_info=e) return failure('upload_failed', {'upload_errors': [err.name for err in e.errors]}) try: session = YubiOtpSession(conn) session.put_configuration( slot, YubiOtpSlotConfiguration(public_id, private_id, key) ) except CommandError as e: logger.debug("Failed to program YubiOTP", exc_info=e) return failure("write error") logger.debug('YubiOTP successfully programmed.') if upload_url: logger.debug('Upload url: %s', upload_url) return success({'upload_url': upload_url})
def parse_modhex_or_bcd(value): try: return True, modhex_decode(value) except ValueError: try: int(value) return False, bytes.fromhex(value) except ValueError: raise ValueError("value must be modhex or decimal")
def yubiotp( ctx, slot, public_id, private_id, key, no_enter, force, serial_public_id, generate_private_id, generate_key, upload, ): """ Program a Yubico OTP credential. """ info = ctx.obj["info"] session = ctx.obj["session"] if public_id and serial_public_id: ctx.fail( "Invalid options: --public-id conflicts with --serial-public-id.") if private_id and generate_private_id: ctx.fail( "Invalid options: --private-id conflicts with --generate-public-id." ) if upload and force: ctx.fail("Invalid options: --upload conflicts with --force.") if key and generate_key: ctx.fail("Invalid options: --key conflicts with --generate-key.") if not public_id: if serial_public_id: serial = session.get_serial() if serial is None: cli_fail("Serial number not set, public ID must be provided") public_id = modhex_encode(b"\xff\x00" + struct.pack(b">I", serial)) click.echo(f"Using YubiKey serial as public ID: {public_id}") elif force: ctx.fail("Public ID not given. Please remove the --force flag, or " "add the --serial-public-id flag or --public-id option.") else: public_id = click_prompt("Enter public ID") try: public_id = modhex_decode(public_id) except KeyError: ctx.fail("Invalid public ID, must be modhex.") if not private_id: if generate_private_id: private_id = os.urandom(6) click.echo( f"Using a randomly generated private ID: {private_id.hex()}") elif force: ctx.fail( "Private ID not given. Please remove the --force flag, or " "add the --generate-private-id flag or --private-id option.") else: private_id = click_prompt("Enter private ID") private_id = bytes.fromhex(private_id) if not key: if generate_key: key = os.urandom(16) click.echo(f"Using a randomly generated secret key: {key.hex()}") elif force: ctx.fail( "Secret key not given. Please remove the --force flag, or " "add the --generate-key flag or --key option.") else: key = click_prompt("Enter secret key") key = bytes.fromhex(key) if not upload and not force: upload = click.confirm("Upload credential to YubiCloud?", abort=False, err=True) if upload: try: upload_url = prepare_upload_key( key, public_id, private_id, serial=info.serial, user_agent="ykman/" + __version__, ) click.echo("Upload to YubiCloud initiated successfully.") except PrepareUploadFailed as e: error_msg = "\n".join(e.messages()) cli_fail("Upload to YubiCloud failed.\n" + error_msg) force or click.confirm( f"Program a YubiOTP credential in slot {slot}?", abort=True, err=True) try: session.put_configuration( slot, YubiOtpSlotConfiguration(public_id, private_id, key).append_cr(not no_enter), ctx.obj["access_code"], ctx.obj["access_code"], ) except CommandError as e: _failed_to_write_msg(ctx, e) if upload: click.echo("Opening upload form in browser: " + upload_url) webbrowser.open_new_tab(upload_url)