fix: A certificate rejection does not crash the connection

Fixes moxxy/moxxyv2#137.
This commit is contained in:
PapaTutuWawa 2022-11-12 20:56:44 +01:00
parent 848d83dc1f
commit 3172450b70
6 changed files with 100 additions and 5 deletions

View File

@ -12,3 +12,4 @@ analyzer:
- "**/*.g.dart" - "**/*.g.dart"
- "**/*.freezed.dart" - "**/*.freezed.dart"
- "test/" - "test/"
- "integration_test/"

View File

@ -796,6 +796,15 @@ class XmppConnection {
_updateRoutingState(RoutingState.handleStanzas); _updateRoutingState(RoutingState.handleStanzas);
await _onNegotiationsDone(); await _onNegotiationsDone();
} else if (_currentNegotiator!.state == NegotiatorState.error) {
_log.severe('Negotiator returned an error');
_updateRoutingState(RoutingState.error);
await _setConnectionState(XmppConnectionState.error);
_connectionCompleter?.complete(const XmppConnectionResult(false));
_connectionCompleter = null;
_closeSocket();
} }
} }

View File

@ -0,0 +1,64 @@
import 'package:logging/logging.dart';
import 'package:moxxmpp/moxxmpp.dart';
import 'package:moxxmpp_socket_tcp/moxxmpp_socket_tcp.dart';
import 'package:test/test.dart';
Future<void> _runTest(String domain) async {
var gotTLSException = false;
final socket = TCPSocketWrapper(false);
final log = Logger('TestLogger');
socket.getEventStream().listen((event) {
if (event is XmppSocketTLSFailedEvent) {
log.info('Got XmppSocketTLSFailedEvent from socket');
gotTLSException = true;
}
});
final connection = XmppConnection(
ExponentialBackoffReconnectionPolicy(),
socket,
);
connection.registerFeatureNegotiators([
StartTlsNegotiator(),
]);
connection.registerManagers([
DiscoManager(),
RosterManager(),
PingManager(),
MessageManager(),
PresenceManager('http://moxxmpp.example'),
]);
connection.setConnectionSettings(
ConnectionSettings(
jid: JID.fromString('testuser@$domain'),
password: 'abc123',
useDirectTLS: true,
allowPlainAuth: true,
),
);
final result = await connection.connectAwaitable();
expect(result.success, false);
expect(gotTLSException, true);
}
void main() {
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((record) {
print('${record.level.name}: ${record.time}: ${record.message}');
});
for (final domain in [
'self-signed.badxmpp.eu',
'expired.badxmpp.eu',
'wrong-name.badxmpp.eu',
'missing-chain.badxmpp.eu',
// TODO(Unknown): Technically, this one should not fail
//'ecdsa.badxmpp.eu',
]) {
test('$domain with connectAwaitable', () async {
await _runTest(domain);
});
}
}

View File

@ -1,4 +1,5 @@
library moxxmpp_socket_tcp; library moxxmpp_socket_tcp;
export 'src/events.dart';
export 'src/record.dart'; export 'src/record.dart';
export 'src/socket.dart'; export 'src/socket.dart';

View File

@ -0,0 +1,4 @@
import 'package:moxxmpp/moxxmpp.dart';
/// Triggered when TLS errors occur
class XmppSocketTLSFailedEvent extends XmppSocketEvent {}

View File

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:moxxmpp/moxxmpp.dart'; import 'package:moxxmpp/moxxmpp.dart';
import 'package:moxxmpp_socket_tcp/src/events.dart';
import 'package:moxxmpp_socket_tcp/src/record.dart'; import 'package:moxxmpp_socket_tcp/src/record.dart';
import 'package:moxxmpp_socket_tcp/src/rfc_2782.dart'; import 'package:moxxmpp_socket_tcp/src/rfc_2782.dart';
@ -66,6 +67,7 @@ class TCPSocketWrapper extends BaseSocketWrapper {
return false; return false;
} }
var failedDueToTLS = false;
results.sort(srvRecordSortComparator); results.sort(srvRecordSortComparator);
for (final srv in results) { for (final srv in results) {
try { try {
@ -91,12 +93,20 @@ class TCPSocketWrapper extends BaseSocketWrapper {
_secure = true; _secure = true;
_log.finest('Success!'); _log.finest('Success!');
return true; return true;
} on SocketException catch(e) { } on Exception catch(e) {
_log.finest('Failure! $e'); _log.finest('Failure! $e');
_ignoreSocketClosure = false; _ignoreSocketClosure = false;
if (e is HandshakeException) {
failedDueToTLS = true;
}
} }
} }
if (failedDueToTLS) {
_eventStream.add(XmppSocketTLSFailedEvent());
}
return false; return false;
} }
@ -118,7 +128,7 @@ class TCPSocketWrapper extends BaseSocketWrapper {
_ignoreSocketClosure = false; _ignoreSocketClosure = false;
_log.finest('Success!'); _log.finest('Success!');
return true; return true;
} on SocketException catch(e) { } on Exception catch(e) {
_log.finest('Failure! $e'); _log.finest('Failure! $e');
_ignoreSocketClosure = false; _ignoreSocketClosure = false;
continue; continue;
@ -142,7 +152,7 @@ class TCPSocketWrapper extends BaseSocketWrapper {
); );
_log.finest('Success!'); _log.finest('Success!');
return true; return true;
} on SocketException catch(e) { } on Exception catch(e) {
_log.finest('Failure! $e'); _log.finest('Failure! $e');
_ignoreSocketClosure = false; _ignoreSocketClosure = false;
return false; return false;
@ -183,8 +193,14 @@ class TCPSocketWrapper extends BaseSocketWrapper {
_ignoreSocketClosure = false; _ignoreSocketClosure = false;
_setupStreams(); _setupStreams();
return true; return true;
} on SocketException { } on Exception catch (e) {
_log.severe('Failed to secure socket: $e');
_ignoreSocketClosure = false; _ignoreSocketClosure = false;
if (e is HandshakeException) {
_eventStream.add(XmppSocketTLSFailedEvent());
}
return false; return false;
} }
} }
@ -293,7 +309,7 @@ class TCPSocketWrapper extends BaseSocketWrapper {
try { try {
_socket!.write(data); _socket!.write(data);
} on SocketException catch (e) { } on Exception catch (e) {
_log.severe(e); _log.severe(e);
_eventStream.add(XmppSocketErrorEvent(e)); _eventStream.add(XmppSocketErrorEvent(e));
} }