Exemple #1
0
    def Authenticate(self, app_id, challenge, registered_keys):
        """Authenticates app_id with the security key.

    Executes the U2F authentication/signature flow with the security key.

    Args:
      app_id: The app_id to register the security key against.
      challenge: Server challenge passed to the security key.
      registered_keys: List of keys already registered for this app_id+user.

    Returns:
      SignResponse with client_data, key_handle, and signature_data.  The client
      data is an object, while the signature_data is encoded in FIDO U2F binary
      format.

    Raises:
      U2FError: There was some kind of problem with registration (e.g.
        the device was already registered or there was a timeout while
        waiting for the test of user presence.)
    """
        client_data = model.ClientData(model.ClientData.TYP_AUTHENTICATION,
                                       challenge, self.origin)
        app_param = self.InternalSHA256(app_id)
        challenge_param = self.InternalSHA256(client_data.GetJson())
        num_invalid_keys = 0
        for key in registered_keys:
            try:
                if key.version != 'U2F_V2':
                    continue
                for _ in range(10):
                    try:
                        resp = self.security_key.CmdAuthenticate(
                            challenge_param, app_param, key.key_handle)
                        return model.SignResponse(key.key_handle, resp,
                                                  client_data)
                    except errors.TUPRequiredError:
                        self.security_key.CmdWink()
                        time.sleep(0.5)
            except errors.InvalidKeyHandleError:
                num_invalid_keys += 1
                continue
            except errors.HardwareError as e:
                raise errors.U2FError(errors.U2FError.BAD_REQUEST, e)

        if num_invalid_keys == len(registered_keys):
            # In this case, all provided keys were invalid.
            raise errors.U2FError(errors.U2FError.DEVICE_INELIGIBLE)

        # In this case, the TUP was not pressed.
        raise errors.U2FError(errors.U2FError.TIMEOUT)
    def testSignMultipleSuccess(self, mock_get_u2f_method):
        """Test signing with multiple keys registered and one is eligible."""
        # Prepare u2f mocks
        mock_u2f = mock.MagicMock()
        mock_get_u2f_method.return_value = mock_u2f

        mock_authenticate = mock.MagicMock()
        mock_u2f.Authenticate = mock_authenticate

        return_value = model.SignResponse(
            base64.urlsafe_b64decode(SIGN_SUCCESS['key_handle_encoded']),
            base64.urlsafe_b64decode(SIGN_SUCCESS['signature_data_encoded']),
            SIGN_SUCCESS['client_data'])

        mock_authenticate.side_effect = [
            errors.U2FError(errors.U2FError.DEVICE_INELIGIBLE), return_value
        ]

        # Call LocalAuthenticator
        challenge_item = {
            'key': SIGN_SUCCESS['registered_key'],
            'challenge': SIGN_SUCCESS['challenge']
        }
        challenge_data = [challenge_item, challenge_item]

        authenticator = localauthenticator.LocalAuthenticator('testorigin')
        response = authenticator.Authenticate(SIGN_SUCCESS['app_id'],
                                              challenge_data)

        # Validate that u2f authenticate was called with the correct values
        self.assertTrue(mock_authenticate.called)
        authenticate_args = mock_authenticate.call_args[0]
        self.assertEqual(len(authenticate_args), 3)
        self.assertEqual(authenticate_args[0], SIGN_SUCCESS['app_id'])
        self.assertEqual(authenticate_args[1], SIGN_SUCCESS['challenge'])
        registered_keys = authenticate_args[2]
        self.assertEqual(len(registered_keys), 1)
        self.assertEqual(registered_keys[0], SIGN_SUCCESS['registered_key'])

        # Validate authenticator response
        self.assertEquals(response.get('clientData'),
                          SIGN_SUCCESS['client_data_encoded'])
        self.assertEquals(response.get('signatureData'),
                          SIGN_SUCCESS['signature_data_encoded'])
        self.assertEquals(response.get('applicationId'),
                          SIGN_SUCCESS['app_id'])
        self.assertEquals(response.get('keyHandle'),
                          SIGN_SUCCESS['key_handle_encoded'])
    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()
        mock_u2f.Authenticate = mock_authenticate

        mock_authenticate.return_value = model.SignResponse(
            base64.urlsafe_b64decode(SIGN_SUCCESS['key_handle_encoded']),
            base64.urlsafe_b64decode(SIGN_SUCCESS['signature_data_encoded']),
            SIGN_SUCCESS['client_data'])

        # Call LocalAuthenticator
        challenge_data = [{
            'key': SIGN_SUCCESS['registered_key'],
            'challenge': SIGN_SUCCESS['challenge']
        }]
        authenticator = localauthenticator.LocalAuthenticator('testorigin')
        self.assertTrue(authenticator.IsAvailable())
        response = authenticator.Authenticate(SIGN_SUCCESS['app_id'],
                                              challenge_data)

        # Validate that u2f authenticate was called with the correct values
        self.assertTrue(mock_authenticate.called)
        authenticate_args = mock_authenticate.call_args[0]
        self.assertEqual(len(authenticate_args), 3)
        self.assertEqual(authenticate_args[0], SIGN_SUCCESS['app_id'])
        self.assertEqual(authenticate_args[1], SIGN_SUCCESS['challenge'])
        registered_keys = authenticate_args[2]
        self.assertEqual(len(registered_keys), 1)
        self.assertEqual(registered_keys[0], SIGN_SUCCESS['registered_key'])

        # Validate authenticator response
        self.assertEquals(response.get('clientData'),
                          SIGN_SUCCESS['client_data_encoded'])
        self.assertEquals(response.get('signatureData'),
                          SIGN_SUCCESS['signature_data_encoded'])
        self.assertEquals(response.get('applicationId'),
                          SIGN_SUCCESS['app_id'])
        self.assertEquals(response.get('keyHandle'),
                          SIGN_SUCCESS['key_handle_encoded'])
 def Authenticate(self, unused_app_id, challenge, unused_registered_keys):
     client_data = model.ClientData(
         model.ClientData.TYP_AUTHENTICATION,
         challenge,
         'some_origin'.encode('ascii'))
     return model.SignResponse('key_handle', 'resp', client_data)