Files
sdk/tests/standalone/io/secure_socket_bad_data_test.dart
T
Zach Anderson afb490adbc [dart:io] Provide modern Dart-styled constants
This CL updates dart:io but not dart:_http. It updates the sdk sources,
the patch files, and tests.

Change-Id: I64c3da407f09fa2bc6eec582049c4ae3a8afbe6d
Reviewed-on: https://dart-review.googlesource.com/52990
Commit-Queue: Zach Anderson <zra@google.com>
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
2018-05-03 17:00:14 +00:00

153 lines
4.8 KiB
Dart

// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// VMOptions=
// VMOptions=--short_socket_read
// VMOptions=--short_socket_write
// VMOptions=--short_socket_read --short_socket_write
import "dart:async";
import "dart:io";
import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";
InternetAddress HOST;
const CERTIFICATE = "localhost_cert";
// This test sends corrupt data in the middle of a secure network connection.
// This tests the error handling of RawSecureSocket.
// A RawSocket connection is upgraded to a secure connection, so that we
// have a reference to the underlying socket. Then we send some
// unencrypted data on it, in the middle of an encrypted data transfer.
// This test creates a server and then connects a client to the server.
// After connecting, the connection is upgraded to a secure connection.
// The client writes data to the server, then writes unencrypted data
// on the underlying socket. When the server gets the unencrypted data,
// this causes an error in the NSS code. When the NSS code is in debug
// mode, bad data on the connection can cause an assertion failure, rather
// than an exception.
const messageSize = 1000;
List<int> createTestData() {
List<int> data = new List<int>(messageSize);
for (int i = 0; i < messageSize; i++) {
data[i] = i & 0xff;
}
return data;
}
void verifyTestData(List<int> data) {
Expect.equals(messageSize, data.length);
List<int> expected = createTestData();
for (int i = 0; i < messageSize; i++) {
Expect.equals(expected[i], data[i]);
}
}
Future runServer(RawSocket client) {
final completer = new Completer();
final dataReceived = new List<int>(messageSize);
int bytesRead = 0;
client.writeEventsEnabled = false;
client.listen((event) {
switch (event) {
case RawSocketEvent.read:
Expect.isTrue(client.available() > 0);
var buffer = client.read(200);
dataReceived.setRange(bytesRead, bytesRead + buffer.length, buffer);
bytesRead += buffer.length;
if (bytesRead == dataReceived.length) {
verifyTestData(dataReceived);
}
break;
case RawSocketEvent.write:
Expect.fail('WRITE event received');
break;
case RawSocketEvent.readClosed:
Expect.fail('READ_CLOSED event received');
client.shutdown(SocketDirection.send);
completer.complete(null);
break;
}
}, onError: (e) {
Expect.isTrue(e is TlsException);
Expect.isTrue(e.toString().contains(
'received a record with an incorrect Message Authentication Code'));
completer.complete(null);
});
return completer.future;
}
Future<RawSocket> runClient(List sockets) {
final RawSocket baseSocket = sockets[0];
final RawSecureSocket socket = sockets[1];
final data = createTestData();
var completer = new Completer();
void tryComplete() {
if (completer != null) {
completer.complete(null);
completer = null;
}
}
int bytesWritten = 0;
socket.listen((event) {
switch (event) {
case RawSocketEvent.read:
Expect.fail('READ event received');
break;
case RawSocketEvent.write:
if (bytesWritten < data.length) {
bytesWritten += socket.write(data, bytesWritten);
}
if (bytesWritten < data.length) {
socket.writeEventsEnabled = true;
}
if (bytesWritten == data.length) {
baseSocket.write(data, 0, 300);
socket.shutdown(SocketDirection.send);
}
break;
case RawSocketEvent.readClosed:
tryComplete();
break;
}
}, onError: (e) {
Expect.isTrue(e is IOException);
tryComplete();
});
return completer.future;
}
Future<List> connectClient(int port, bool hostnameInConnect) =>
RawSocket.connect(HOST, port).then((socket) => (hostnameInConnect
? RawSecureSocket.secure(socket)
: RawSecureSocket.secure(socket, host: HOST))
.then((secureSocket) => [socket, secureSocket]));
Future test(bool hostnameInConnect) {
return RawServerSocket.bind(HOST, 0).then((server) {
server.listen((client) {
RawSecureSocket.secureServer(client, CERTIFICATE).then((secureClient) {
Expect.throws(() => client.add([0]));
return runServer(secureClient);
}, onError: (e) {
Expect.isTrue(e is HandshakeException);
}).whenComplete(server.close);
});
return connectClient(server.port, hostnameInConnect).then(runClient);
});
}
main() {
asyncStart();
InternetAddress.lookup("localhost").then((hosts) {
HOST = hosts.first;
return Future.wait([test(false), test(true)]);
}).then((_) => asyncEnd());
}