|  | // 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 | 
|  |  | 
|  | import "dart:async"; | 
|  | import "dart:io"; | 
|  |  | 
|  | import "package:expect/async_helper.dart"; | 
|  | import "package:expect/expect.dart"; | 
|  |  | 
|  | late 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, 0); | 
|  | for (int i = 0; i < messageSize; i++) { | 
|  | data[i] = i & 0xff; | 
|  | } | 
|  | return data; | 
|  | } | 
|  |  | 
|  | List<int> createHandshakeTestData() { | 
|  | List<int> data = new List<int>.filled(handshakeMessageSize, 0); | 
|  | 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 = <int>[]; | 
|  | 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 runClientHandshake(Socket socket) { | 
|  | var completer = new Completer(); | 
|  | var dataReceived = <int>[]; | 
|  | 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(); | 
|  | }); | 
|  | } |