blob: 963fb74e20be1b7d96f2a2696f5d39489080a9c7 [file] [log] [blame]
// Copyright (c) 2014, 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.
import 'dart:io';
import 'dart:convert';
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
const String MAX_LEN_ERROR =
'Length of protocol must be between 1 and 255';
const String MAX_MSG_LEN_ERROR =
'The maximum message length supported is 2^15-1';
void InitializeSSL() {
var testPkcertDatabase = Platform.script.resolve('pkcert').toFilePath();
SecureSocket.initialize(database: testPkcertDatabase,
password: 'dartdart');
}
// Tests that client/server with same protocol can securly establish a
// connection, negogiate the protocol and can send data to each other.
void testSuccessfulAlpnNegogiationConnection(List<String> clientProtocols,
List<String> serverProtocols,
String selectedProtocol) {
asyncStart();
SecureServerSocket.bind('localhost', 0, 'localhost_cert',
supportedProtocols: serverProtocols).then((SecureServerSocket server) {
asyncStart();
server.first.then((SecureSocket socket) {
Expect.equals(selectedProtocol, socket.selectedProtocol);
socket..write('server message')..close();
socket.transform(ASCII.decoder).join('').then((String s) {
Expect.equals('client message', s);
asyncEnd();
});
});
asyncStart();
SecureSocket.connect('localhost', server.port,
supportedProtocols: clientProtocols).then((socket) {
Expect.equals(selectedProtocol, socket.selectedProtocol);
socket..write('client message')..close();
socket.transform(ASCII.decoder).join('').then((String s) {
Expect.equals('server message', s);
server.close();
asyncEnd();
});
});
asyncEnd();
});
}
void testFailedAlpnNegogiationConnection(List<String> clientProtocols,
List<String> serverProtocols) {
asyncStart();
SecureServerSocket.bind('localhost', 0, 'localhost_cert',
supportedProtocols: serverProtocols).then((SecureServerSocket server) {
asyncStart();
server.first.catchError((error, stack) {
Expect.isTrue(error is HandshakeException);
asyncEnd();
});
asyncStart();
SecureSocket.connect('localhost',
server.port,
supportedProtocols: clientProtocols)
.catchError((error, stack) {
Expect.isTrue(error is HandshakeException);
asyncEnd();
});
asyncEnd();
});
}
void testInvalidArgumentsLongName(List<String> protocols,
bool isLenError,
bool isMsgLenError) {
asyncStart();
SecureServerSocket.bind('localhost', 0, 'localhost_cert',
supportedProtocols: protocols).then((SecureServerSocket server) {
asyncStart();
server.first.catchError((error, stack) {
String errorString = '${(error as ArgumentError)}';
if (isLenError) {
Expect.isTrue(errorString.contains(MAX_LEN_ERROR));
} else if (isMsgLenError) {
Expect.isTrue(errorString.contains(MAX_MSG_LEN_ERROR));
} else {
throw 'unreachable';
}
asyncEnd();
});
asyncStart();
SecureSocket.connect('localhost',
server.port,
supportedProtocols: protocols)
.catchError((error, stack) {
String errorString = '${(error as ArgumentError)}';
if (isLenError) {
Expect.isTrue(errorString.contains(MAX_LEN_ERROR));
} else if (isMsgLenError) {
Expect.isTrue(errorString.contains(MAX_MSG_LEN_ERROR));
} else {
throw 'unreachable';
}
asyncEnd();
});
asyncEnd();
});
}
main() {
InitializeSSL();
final longname256 = 'p' * 256;
final String longname255 = 'p' * 255;
final String strangelongname255 = 'ø' + 'p' * 253;
final String strangelongname256 = 'ø' + 'p' * 254;
// This produces a message of (1 << 15)-2 bytes (1 length and 1 ascii byte).
final List<String> allProtocols = new Iterable.generate(
(1 << 14) - 1, (i) => '0').toList();
// This produces a message of (1 << 15) bytes (1 length and 1 ascii byte).
final List<String> allProtocolsPlusOne = new Iterable.generate(
(1 << 14), (i) => '0').toList();
// Protocols are in order of decreasing priority. First matching protocol
// will be taken.
// Test successfull negotiation, including priority.
testSuccessfulAlpnNegogiationConnection(['a'],
['a'],
'a');
testSuccessfulAlpnNegogiationConnection([longname255],
[longname255],
longname255);
testSuccessfulAlpnNegogiationConnection([strangelongname255],
[strangelongname255],
strangelongname255);
testSuccessfulAlpnNegogiationConnection(allProtocols,
allProtocols,
'0');
testSuccessfulAlpnNegogiationConnection(['a', 'b', 'c'],
['a', 'b', 'c'],
'a');
testSuccessfulAlpnNegogiationConnection(['a', 'b', 'c'],
['c'],
'c');
// Server precedence.
testSuccessfulAlpnNegogiationConnection(['a', 'b', 'c'],
['c', 'b', 'a'],
'a');
testSuccessfulAlpnNegogiationConnection(['c'],
['a', 'b', 'c'],
'c');
testSuccessfulAlpnNegogiationConnection(['s1', 'b', 'e1'],
['s2', 'b', 'e2'],
'b');
// Test no protocol negotiation support
testSuccessfulAlpnNegogiationConnection(null,
null,
null);
testSuccessfulAlpnNegogiationConnection(['a', 'b', 'c'],
null,
null);
testSuccessfulAlpnNegogiationConnection(null,
['a', 'b', 'c'],
null);
testSuccessfulAlpnNegogiationConnection([],
[],
null);
testSuccessfulAlpnNegogiationConnection(['a', 'b', 'c'],
[],
null);
testSuccessfulAlpnNegogiationConnection([],
['a', 'b', 'c'],
null);
// Test non-overlapping protocols.
testFailedAlpnNegogiationConnection(['a'], ['b']);
// Test too short / too long protocol names.
testInvalidArgumentsLongName([longname256], true, false);
testInvalidArgumentsLongName([strangelongname256], true, false);
testInvalidArgumentsLongName([''], true, false);
testInvalidArgumentsLongName(allProtocolsPlusOne, false, true);
testInvalidArgumentsLongName(allProtocolsPlusOne, false, true);
}