def testAuthenticateAllKeysInvalid(self): mock_sk = mock.MagicMock() mock_sk.CmdAuthenticate.side_effect = errors.InvalidKeyHandleError mock_sk.CmdVersion.return_value = b'U2F_V2' u2f_api = u2f.U2FInterface(mock_sk) with self.assertRaises(errors.U2FError) as cm: u2f_api.Authenticate( 'testapp', b'ABCD', [model.RegisteredKey('khA'), model.RegisteredKey('khB')]) self.assertEquals(cm.exception.code, errors.U2FError.DEVICE_INELIGIBLE) u2f_api = u2f.U2FInterface(mock_sk)
def InternalObtainCredentials(self, metadata): sk = metadata['securityKey'] challenges = sk['challenges'] app_id = sk['applicationId'] challenge_data = [] for c in challenges: kh = c['keyHandle'].encode('ascii') key = model.RegisteredKey(bytearray(base64.urlsafe_b64decode(kh))) challenge = c['challenge'].encode('ascii') challenge = base64.urlsafe_b64decode(challenge) challenge_data.append({'key': key, 'challenge': challenge}) try: api = authenticator.CreateCompositeAuthenticator(REAUTH_ORIGIN) response = api.Authenticate(app_id, challenge_data, print_callback=GetPrintCallback()) return {'securityKey': response} except u2ferrors.U2FError as e: if e.code == u2ferrors.U2FError.DEVICE_INELIGIBLE: GetPrintCallback()('Ineligible security key.\n') elif e.code == u2ferrors.U2FError.TIMEOUT: GetPrintCallback()( 'Timed out while waiting for security key touch.\n') else: raise e except u2ferrors.NoDeviceFoundError: GetPrintCallback()('No security key found.\n') return None
def handle(self, packet) -> bool: digest = bytestostr(packet[3]) if not digest.startswith("u2f:"): log("%s is not a u2f challenge", digest) return False try: from pyu2f import model #@UnresolvedImport from pyu2f.u2f import GetLocalU2FInterface #@UnresolvedImport except ImportError as e: log.warn("Warning: cannot use u2f authentication handler") log.warn(" %s", e) return False if not is_debug_enabled("auth"): logging.getLogger("pyu2f.hardware").setLevel(logging.INFO) logging.getLogger("pyu2f.hidtransport").setLevel(logging.INFO) dev = GetLocalU2FInterface() APP_ID = os.environ.get("XPRA_U2F_APP_ID", "Xpra") key_handle = self.get_key_handle() if not key_handle: return False key = model.RegisteredKey(key_handle) #use server salt as challenge directly challenge = packet[1] log.info("activate your U2F device for authentication") response = dev.Authenticate(APP_ID, challenge, [key]) sig = response.signature_data client_data = response.client_data log("process_challenge_u2f client data=%s, signature=%s", client_data, binascii.hexlify(sig)) self.client.do_send_challenge_reply(bytes(sig), client_data.origin) return True
def testAuthenticateSuccessSkipInvalidVersion(self): mock_sk = mock.MagicMock() mock_sk.CmdAuthenticate.return_value = 'signature' mock_sk.CmdVersion.return_value = b'U2F_V2' u2f_api = u2f.U2FInterface(mock_sk) resp = u2f_api.Authenticate('testapp', b'ABCD', [ model.RegisteredKey('khA', version='U2F_V3'), model.RegisteredKey('khB') ]) self.assertEquals(mock_sk.CmdAuthenticate.call_count, 1) self.assertEquals(mock_sk.CmdWink.call_count, 0) self.assertEquals(resp.key_handle, 'khB') self.assertEquals(resp.client_data.raw_server_challenge, b'ABCD') self.assertEquals(resp.client_data.typ, 'navigator.id.getAssertion') self.assertEquals(resp.signature_data, 'signature')
def testAuthenticateTimeout(self): mock_sk = mock.MagicMock() mock_sk.CmdAuthenticate.side_effect = errors.TUPRequiredError mock_sk.CmdVersion.return_value = b'U2F_V2' u2f_api = u2f.U2FInterface(mock_sk) # Speed up the test by mocking out sleep to do nothing with mock.patch.object(u2f, 'time') as _: with self.assertRaises(errors.U2FError) as cm: u2f_api.Authenticate('testapp', b'ABCD', [model.RegisteredKey('khA')]) self.assertEquals(cm.exception.code, errors.U2FError.TIMEOUT) self.assertEquals(mock_sk.CmdAuthenticate.call_count, 30) self.assertEquals(mock_sk.CmdWink.call_count, 30)
def process_challenge_u2f(self, packet): digest = packet[3] if not digest.startswith(b"u2f:"): authlog("%s is not a u2f challenge", digest) return False import binascii import logging if not is_debug_enabled("auth"): logging.getLogger("pyu2f.hardware").setLevel(logging.INFO) logging.getLogger("pyu2f.hidtransport").setLevel(logging.INFO) from pyu2f import model from pyu2f.u2f import GetLocalU2FInterface dev = GetLocalU2FInterface() APP_ID = os.environ.get("XPRA_U2F_APP_ID", "Xpra") key_handle_str = os.environ.get("XPRA_U2F_KEY_HANDLE") authlog("process_challenge_u2f XPRA_U2F_KEY_HANDLE=%s", key_handle_str) if not key_handle_str: #try to load the key handle from the user conf dir(s): from xpra.platform.paths import get_user_conf_dirs info = self._protocol.get_info(False) key_handle_filenames = [] for hostinfo in ("-%s" % info.get("host", ""), ""): key_handle_filenames += [ os.path.join(d, "u2f-keyhandle%s.hex" % hostinfo) for d in get_user_conf_dirs() ] for filename in key_handle_filenames: p = osexpand(filename) key_handle_str = load_binary_file(p) authlog("key_handle_str(%s)=%s", p, key_handle_str) if key_handle_str: key_handle_str = key_handle_str.rstrip(b" \n\r") break if not key_handle_str: authlog.warn("Warning: no U2F key handle found") return False authlog("process_challenge_u2f key_handle=%s", key_handle_str) key_handle = binascii.unhexlify(key_handle_str) key = model.RegisteredKey(key_handle) #use server salt as challenge directly challenge = packet[1] authlog.info("activate your U2F device for authentication") response = dev.Authenticate(APP_ID, challenge, [key]) sig = response.signature_data client_data = response.client_data authlog("process_challenge_u2f client data=%s, signature=%s", client_data, binascii.hexlify(sig)) self.do_send_challenge_reply(bytes(sig), client_data.origin) return True
def testAuthenticateError(self): mock_sk = mock.MagicMock() mock_sk.CmdAuthenticate.side_effect = errors.ApduError(0xff, 0xff) mock_sk.CmdVersion.return_value = b'U2F_V2' u2f_api = u2f.U2FInterface(mock_sk) with self.assertRaises(errors.U2FError) as cm: u2f_api.Authenticate('testapp', b'ABCD', [model.RegisteredKey('khA')]) self.assertEquals(cm.exception.code, errors.U2FError.BAD_REQUEST) self.assertEquals(cm.exception.cause.sw1, 0xff) self.assertEquals(cm.exception.cause.sw2, 0xff) self.assertEquals(mock_sk.CmdAuthenticate.call_count, 1) self.assertEquals(mock_sk.CmdWink.call_count, 0)
def testRegisterFailAlreadyRegistered(self): mock_sk = mock.MagicMock() mock_sk.CmdAuthenticate.side_effect = errors.TUPRequiredError mock_sk.CmdVersion.return_value = b'U2F_V2' u2f_api = u2f.U2FInterface(mock_sk) with self.assertRaises(errors.U2FError) as cm: u2f_api.Register('testapp', b'ABCD', [model.RegisteredKey('khA')]) self.assertEquals(cm.exception.code, errors.U2FError.DEVICE_INELIGIBLE) self.assertEquals(mock_sk.CmdAuthenticate.call_count, 1) # Should be "Check only" self.assertTrue(mock_sk.CmdAuthenticate.call_args[0][3]) self.assertEquals(mock_sk.CmdRegister.call_count, 0) self.assertEquals(mock_sk.CmdWink.call_count, 0)
def testAuthenticateSuccessWithTUP(self): mock_sk = mock.MagicMock() mock_sk.CmdAuthenticate.side_effect = [ errors.TUPRequiredError, 'signature' ] mock_sk.CmdVersion.return_value = b'U2F_V2' u2f_api = u2f.U2FInterface(mock_sk) resp = u2f_api.Authenticate('testapp', b'ABCD', [model.RegisteredKey('khA')]) self.assertEquals(mock_sk.CmdAuthenticate.call_count, 2) self.assertEquals(mock_sk.CmdWink.call_count, 1) self.assertEquals(resp.key_handle, 'khA') self.assertEquals(resp.client_data.raw_server_challenge, b'ABCD') self.assertEquals(resp.client_data.typ, 'navigator.id.getAssertion') self.assertEquals(resp.signature_data, 'signature')
def testRegisterSuccessWithPreviousKeys(self): mock_sk = mock.MagicMock() mock_sk.CmdAuthenticate.side_effect = errors.InvalidKeyHandleError mock_sk.CmdRegister.side_effect = [errors.TUPRequiredError, 'regdata'] mock_sk.CmdVersion.return_value = b'U2F_V2' u2f_api = u2f.U2FInterface(mock_sk) resp = u2f_api.Register('testapp', b'ABCD', [model.RegisteredKey('khA')]) self.assertEquals(mock_sk.CmdAuthenticate.call_count, 1) # Should be "Check only" self.assertTrue(mock_sk.CmdAuthenticate.call_args[0][3]) self.assertEquals(mock_sk.CmdRegister.call_count, 2) self.assertEquals(mock_sk.CmdWink.call_count, 1) self.assertEquals(resp.client_data.raw_server_challenge, b'ABCD') self.assertEquals(resp.client_data.typ, 'navigator.id.finishEnrollment') self.assertEquals(resp.registration_data, 'regdata')
'key_handle_encoded': ('iBbl9-VYt-XSdWeHVNX-gfQcXGzlrAQ7BcngVNUxWijIQQlnZEI' '4Vb0Bp2ydBCbIQu_5rNlKqPH6NK1TtnM7fA'), 'origin': 'test_origin', 'signature_data_encoded': ('AQAAAI8wRQIhALlIPo6Hg8HwzELdYRIXnAnpsiHYCSXHex' 'CS34eiS2ixAiBt3TRmKE1A9WyMjc3JGrGI7gSPg-QzDSNL' 'aIj7JwcCTA'), 'client_data_encoded': ('eyJjaGFsbGVuZ2UiOiAiWVhOa1ptRnpaR1kiLCAib3JpZ2luI' 'jogInRlc3Rfb3JpZ2luIiwgInR5cCI6ICJuYXZpZ2F0b3IuaW' 'QuZ2V0QXNzZXJ0aW9uIn0'), 'u2f_version': 'U2F_V2', 'registered_key': model.RegisteredKey( base64.urlsafe_b64decode( 'iBbl9-VYt-XSdWeHVNX-gfQcXGzlrAQ7BcngVNUxWijIQQlnZEI4Vb0Bp2ydBCbIQu' '_5rNlKqPH6NK1TtnM7fA==')) } @mock.patch.object(sys, 'stderr', new=mock.MagicMock()) class CustomAuthenticatorTest(unittest.TestCase): @mock.patch.object(customauthenticator.os.environ, 'get', return_value=None) def testEnvVarNotSet(self, os_get_method): authenticator = customauthenticator.CustomAuthenticator('testorigin') self.assertFalse(authenticator.IsAvailable(), 'Should return false when no env var is present')
'qhJtbTQvsU0BmLLpDWes-3zFGbegR2wp1mv5BJ2BwC0=', 'key_handle_encoded': ('iBbl9-VYt-XSdWeHVNX-gfQcXGzlrAQ7BcngVNUxWijIQQlnZEI' '4Vb0Bp2ydBCbIQu_5rNlKqPH6NK1TtnM7fA=='), 'origin': 'test_origin', 'signature_data_encoded': ('AQAAAI8wRQIhALlIPo6Hg8HwzELdYRIXnAnpsiHYCSXHex' 'CS34eiS2ixAiBt3TRmKE1A9WyMjc3JGrGI7gSPg-QzDSNL' 'aIj7JwcCTA=='), 'client_data_encoded': ('eyJjaGFsbGVuZ2UiOiAiWVhOa1ptRnpaR1kiLCAib3JpZ2luI' 'jogInRlc3Rfb3JpZ2luIiwgInR5cCI6ICJuYXZpZ2F0b3IuaW' 'QuZ2V0QXNzZXJ0aW9uIn0='), 'u2f_version': 'U2F_V2' } SIGN_SUCCESS['registered_key'] = model.RegisteredKey( base64.urlsafe_b64decode(SIGN_SUCCESS['key_handle_encoded'])) SIGN_SUCCESS['client_data'] = model.ClientData( model.ClientData.TYP_AUTHENTICATION, SIGN_SUCCESS['challenge'], SIGN_SUCCESS['origin']) @mock.patch.object(sys, 'stderr', new=mock.MagicMock()) class LocalAuthenticatorTest(unittest.TestCase): @mock.patch.object(localauthenticator.u2f, 'GetLocalU2FInterface') def testSignSuccess(self, mock_get_u2f_method): """Test successful signing with a valid key.""" # Prepare u2f mocks mock_u2f = mock.MagicMock() mock_get_u2f_method.return_value = mock_u2f mock_authenticate = mock.MagicMock()