mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 20:51:19 +00:00
e4cc3c98e5
TEST=ci Bug: Contributes to https://github.com/dart-lang/sdk/issues/49529 Change-Id: Ic129ef2d89f625d9ec6a7a1c301cffddd60b2ff7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/258920 Reviewed-by: Lasse Nielsen <lrn@google.com> Commit-Queue: Michael Thomsen <mit@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
241 lines
7.5 KiB
Dart
241 lines
7.5 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
|
|
// OtherResources=certificates/server_chain.pem
|
|
// OtherResources=certificates/server_key.pem
|
|
// OtherResources=certificates/trusted_certs.pem
|
|
|
|
// @dart = 2.9
|
|
|
|
import "dart:async";
|
|
import "dart:io";
|
|
|
|
import "package:async_helper/async_helper.dart";
|
|
import "package:expect/expect.dart";
|
|
|
|
InternetAddress HOST;
|
|
String localFile(path) => Platform.script.resolve(path).toFilePath();
|
|
List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
|
|
|
|
SecurityContext serverContext = new SecurityContext()
|
|
..useCertificateChain(localFile('certificates/server_chain.pem'))
|
|
..usePrivateKey(localFile('certificates/server_key.pem'),
|
|
password: 'dartdart');
|
|
|
|
SecurityContext clientContext = new SecurityContext()
|
|
..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
|
|
|
|
// This test creates a server and a client connects. After connecting
|
|
// and an optional initial handshake the connection is secured by
|
|
// upgrading to a secure connection The client then writes and the
|
|
// server echos. When the server has finished its echo it
|
|
// half-closes. When the client gets the close event is closes fully.
|
|
//
|
|
// The test can be run in different configurations based on
|
|
// the boolean arguments:
|
|
//
|
|
// handshakeBeforeSecure
|
|
// When this argument is true some initial clear text handshake is done
|
|
// between client and server before the connection is secured. This argument
|
|
// only makes sense when both listenSecure and connectSecure are false.
|
|
//
|
|
// postponeSecure
|
|
// When this argument is false the securing of the server end will
|
|
// happen as soon as the last byte of the handshake before securing
|
|
// has been written. When this argument is true the securing of the
|
|
// server will not happen until the first TLS handshake data has been
|
|
// received from the client. This argument only takes effect when
|
|
// handshakeBeforeSecure is true.
|
|
void test(bool hostnameInConnect, bool handshakeBeforeSecure,
|
|
[bool postponeSecure = false]) {
|
|
asyncStart();
|
|
|
|
const messageSize = 1000;
|
|
const handshakeMessageSize = 100;
|
|
|
|
List<int> createTestData() {
|
|
List<int> data = new List<int>.filled(messageSize, null);
|
|
for (int i = 0; i < messageSize; i++) {
|
|
data[i] = i & 0xff;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
List<int> createHandshakeTestData() {
|
|
List<int> data = new List<int>.filled(handshakeMessageSize, null);
|
|
for (int i = 0; i < handshakeMessageSize; 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]);
|
|
}
|
|
}
|
|
|
|
void verifyHandshakeTestData(List<int> data) {
|
|
Expect.equals(handshakeMessageSize, data.length);
|
|
List<int> expected = createHandshakeTestData();
|
|
for (int i = 0; i < handshakeMessageSize; i++) {
|
|
Expect.equals(expected[i], data[i]);
|
|
}
|
|
}
|
|
|
|
Future runServer(Socket client) {
|
|
var completer = new Completer();
|
|
var dataReceived = <int>[];
|
|
client.listen((data) {
|
|
dataReceived.addAll(data);
|
|
if (dataReceived.length == messageSize) {
|
|
verifyTestData(dataReceived);
|
|
client.add(dataReceived);
|
|
client.close();
|
|
}
|
|
}, onDone: () => completer.complete(null));
|
|
return completer.future;
|
|
}
|
|
|
|
Future<RawSocket> runClient(Socket socket) {
|
|
Completer<RawSocket> completer = new Completer<RawSocket>();
|
|
var dataReceived = <int>[];
|
|
socket.listen((data) {
|
|
dataReceived.addAll(data);
|
|
}, onDone: () {
|
|
Expect.equals(messageSize, dataReceived.length);
|
|
verifyTestData(dataReceived);
|
|
socket.close();
|
|
completer.complete(null);
|
|
});
|
|
socket.add(createTestData());
|
|
return completer.future;
|
|
}
|
|
|
|
Future runServerHandshake(Socket client) {
|
|
var completer = new Completer();
|
|
var dataReceived = [];
|
|
var subscription;
|
|
subscription = client.listen((data) {
|
|
if (dataReceived.length == handshakeMessageSize) {
|
|
Expect.isTrue(postponeSecure);
|
|
subscription.pause();
|
|
completer.complete(data);
|
|
}
|
|
dataReceived.addAll(data);
|
|
if (dataReceived.length == handshakeMessageSize) {
|
|
verifyHandshakeTestData(dataReceived);
|
|
client.add(dataReceived);
|
|
if (!postponeSecure) {
|
|
completer.complete(null);
|
|
}
|
|
}
|
|
}, onDone: () => completer.complete(null));
|
|
return completer.future;
|
|
}
|
|
|
|
Future<Socket> runClientHandshake(Socket socket) {
|
|
var completer = new Completer();
|
|
var dataReceived = [];
|
|
socket.listen((data) {
|
|
dataReceived.addAll(data);
|
|
if (dataReceived.length == handshakeMessageSize) {
|
|
verifyHandshakeTestData(dataReceived);
|
|
completer.complete(null);
|
|
}
|
|
}, onDone: () => Expect.fail("Should not be called"));
|
|
socket.add(createHandshakeTestData());
|
|
return completer.future;
|
|
}
|
|
|
|
Future<SecureSocket> connectClient(int port) {
|
|
if (!handshakeBeforeSecure) {
|
|
return Socket.connect(HOST, port).then((socket) {
|
|
Future<SecureSocket> future;
|
|
if (hostnameInConnect) {
|
|
future = SecureSocket.secure(socket, context: clientContext);
|
|
} else {
|
|
future =
|
|
SecureSocket.secure(socket, host: HOST, context: clientContext);
|
|
}
|
|
return future.then<SecureSocket>((SecureSocket secureSocket) {
|
|
Expect.throws(() {
|
|
socket.add([0]);
|
|
});
|
|
return secureSocket;
|
|
});
|
|
});
|
|
} else {
|
|
return Socket.connect(HOST, port).then((socket) {
|
|
return runClientHandshake(socket).then((_) {
|
|
var future;
|
|
if (hostnameInConnect) {
|
|
future = SecureSocket.secure(socket, context: clientContext);
|
|
} else {
|
|
future =
|
|
SecureSocket.secure(socket, host: HOST, context: clientContext);
|
|
}
|
|
return future.then((secureSocket) {
|
|
Expect.throws(() {
|
|
socket.add([0]);
|
|
});
|
|
return secureSocket;
|
|
});
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
serverReady(server) {
|
|
server.listen((client) {
|
|
if (!handshakeBeforeSecure) {
|
|
SecureSocket.secureServer(client, serverContext).then((secureClient) {
|
|
Expect.throws(() {
|
|
client.add([0]);
|
|
});
|
|
runServer(secureClient).then((_) => server.close());
|
|
});
|
|
} else {
|
|
runServerHandshake(client).then((carryOverData) {
|
|
SecureSocket
|
|
.secureServer(client, serverContext, bufferedData: carryOverData)
|
|
.then((secureClient) {
|
|
Expect.throws(() {
|
|
client.add([0]);
|
|
});
|
|
runServer(secureClient).then((_) => server.close());
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
connectClient(server.port).then(runClient).then((socket) {
|
|
asyncEnd();
|
|
});
|
|
}
|
|
|
|
ServerSocket.bind(HOST, 0).then(serverReady);
|
|
}
|
|
|
|
main() {
|
|
asyncStart();
|
|
InternetAddress.lookup("localhost").then((hosts) {
|
|
HOST = hosts.first;
|
|
test(false, false);
|
|
// TODO(whesse): Enable the test with all argument combinations:
|
|
// test(true, false);
|
|
// test(false, true);
|
|
// test(true, true);
|
|
// test(false, true, true);
|
|
// test(true, true, true);
|
|
asyncEnd();
|
|
});
|
|
}
|