Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of Xpra. 

2# Copyright (C) 2019 Antoine Martin <antoine@xpra.org> 

3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 

4# later version. See the file COPYING for details. 

5 

6import os 

7import logging 

8import binascii 

9 

10from xpra.os_util import bytestostr, load_binary_file, osexpand 

11from xpra.log import Logger, is_debug_enabled 

12 

13log = Logger("auth") 

14 

15 

16class Handler: 

17 

18 def __init__(self, client, **_kwargs): 

19 self.client = client 

20 

21 def __repr__(self): 

22 return "u2f" 

23 

24 def get_digest(self) -> str: 

25 return "u2f" 

26 

27 def handle(self, packet) -> bool: 

28 digest = bytestostr(packet[3]) 

29 if not digest.startswith("u2f:"): 

30 log("%s is not a u2f challenge", digest) 

31 return False 

32 try: 

33 from pyu2f import model #@UnresolvedImport 

34 from pyu2f.u2f import GetLocalU2FInterface #@UnresolvedImport 

35 except ImportError as e: 

36 log.warn("Warning: cannot use u2f authentication handler") 

37 log.warn(" %s", e) 

38 return False 

39 if not is_debug_enabled("auth"): 

40 logging.getLogger("pyu2f.hardware").setLevel(logging.INFO) 

41 logging.getLogger("pyu2f.hidtransport").setLevel(logging.INFO) 

42 dev = GetLocalU2FInterface() 

43 APP_ID = os.environ.get("XPRA_U2F_APP_ID", "Xpra") 

44 key_handle = self.get_key_handle() 

45 if not key_handle: 

46 return False 

47 key = model.RegisteredKey(key_handle) 

48 #use server salt as challenge directly 

49 challenge = packet[1] 

50 log.info("activate your U2F device for authentication") 

51 response = dev.Authenticate(APP_ID, challenge, [key]) 

52 sig = response.signature_data 

53 client_data = response.client_data 

54 log("process_challenge_u2f client data=%s, signature=%s", client_data, binascii.hexlify(sig)) 

55 self.client.do_send_challenge_reply(bytes(sig), client_data.origin) 

56 return True 

57 

58 def get_key_handle(self) -> bytes: 

59 key_handle_str = os.environ.get("XPRA_U2F_KEY_HANDLE") 

60 log("process_challenge_u2f XPRA_U2F_KEY_HANDLE=%s", key_handle_str) 

61 if not key_handle_str: 

62 #try to load the key handle from the user conf dir(s): 

63 from xpra.platform.paths import get_user_conf_dirs 

64 info = self.client._protocol.get_info(False) 

65 key_handle_filenames = [] 

66 for hostinfo in ("-%s" % info.get("host", ""), ""): 

67 for d in get_user_conf_dirs(): 

68 key_handle_filenames.append(os.path.join(d, "u2f-keyhandle%s.hex" % hostinfo)) 

69 for filename in key_handle_filenames: 

70 p = osexpand(filename) 

71 key_handle_str = load_binary_file(p) 

72 log("key_handle_str(%s)=%s", p, key_handle_str) 

73 if key_handle_str: 

74 key_handle_str = key_handle_str.rstrip(b" \n\r") 

75 break 

76 if not key_handle_str: 

77 log.warn("Warning: no U2F key handle found") 

78 return None 

79 log("process_challenge_u2f key_handle=%s", key_handle_str) 

80 return binascii.unhexlify(key_handle_str)