Index: dart/sdk/lib/io/secure_socket.dart |
diff --git a/dart/sdk/lib/io/secure_socket.dart b/dart/sdk/lib/io/secure_socket.dart |
index f11355ae5a2dd5fb5c5e3213c207bbcc5eabe29f..494500987ee88606e685a9fdb94591759f8b9970 100644 |
--- a/dart/sdk/lib/io/secure_socket.dart |
+++ b/dart/sdk/lib/io/secure_socket.dart |
@@ -39,12 +39,14 @@ abstract class SecureSocket implements Socket { |
int port, |
{bool sendClientCertificate: false, |
String certificateName, |
- bool onBadCertificate(X509Certificate certificate)}) { |
+ bool onBadCertificate(X509Certificate certificate), |
+ List<String> supportedProtocols}) { |
return RawSecureSocket.connect(host, |
port, |
sendClientCertificate: sendClientCertificate, |
certificateName: certificateName, |
- onBadCertificate: onBadCertificate) |
+ onBadCertificate: onBadCertificate, |
+ supportedProtocols: supportedProtocols) |
.then((rawSocket) => new SecureSocket._(rawSocket)); |
} |
@@ -122,7 +124,8 @@ abstract class SecureSocket implements Socket { |
String certificateName, |
{List<int> bufferedData, |
bool requestClientCertificate: false, |
- bool requireClientCertificate: false}) { |
+ bool requireClientCertificate: false, |
+ List<String> supportedProtocols}) { |
var completer = new Completer(); |
(socket as dynamic)._detachRaw() |
.then((detachedRaw) { |
@@ -132,7 +135,8 @@ abstract class SecureSocket implements Socket { |
subscription: detachedRaw[1], |
bufferedData: bufferedData, |
requestClientCertificate: requestClientCertificate, |
- requireClientCertificate: requireClientCertificate); |
+ requireClientCertificate: requireClientCertificate, |
+ supportedProtocols: supportedProtocols); |
}) |
.then((raw) { |
completer.complete(new SecureSocket._(raw)); |
@@ -150,6 +154,11 @@ abstract class SecureSocket implements Socket { |
X509Certificate get peerCertificate; |
/** |
+ * Get the protocol which was selected during protocol negotiation. |
+ */ |
+ String get selectedProtocol; |
+ |
+ /** |
* Renegotiate an existing secure connection, renewing the session keys |
* and possibly changing the connection properties. |
* |
@@ -245,7 +254,8 @@ abstract class RawSecureSocket implements RawSocket { |
int port, |
{bool sendClientCertificate: false, |
String certificateName, |
- bool onBadCertificate(X509Certificate certificate)}) { |
+ bool onBadCertificate(X509Certificate certificate), |
+ List<String> supportedProtocols}) { |
_RawSecureSocket._verifyFields( |
host, |
port, |
@@ -260,7 +270,8 @@ abstract class RawSecureSocket implements RawSocket { |
return secure(socket, |
sendClientCertificate: sendClientCertificate, |
certificateName: certificateName, |
- onBadCertificate: onBadCertificate); |
+ onBadCertificate: onBadCertificate, |
+ supportedProtocols: supportedProtocols); |
}); |
} |
@@ -298,7 +309,8 @@ abstract class RawSecureSocket implements RawSocket { |
host, |
bool sendClientCertificate: false, |
String certificateName, |
- bool onBadCertificate(X509Certificate certificate)}) { |
+ bool onBadCertificate(X509Certificate certificate), |
+ List<String> supportedProtocols}) { |
socket.readEventsEnabled = false; |
socket.writeEventsEnabled = false; |
return _RawSecureSocket.connect( |
@@ -309,7 +321,8 @@ abstract class RawSecureSocket implements RawSocket { |
socket: socket, |
subscription: subscription, |
sendClientCertificate: sendClientCertificate, |
- onBadCertificate: onBadCertificate); |
+ onBadCertificate: onBadCertificate, |
+ supportedProtocols: supportedProtocols); |
} |
/** |
@@ -341,7 +354,8 @@ abstract class RawSecureSocket implements RawSocket { |
{StreamSubscription subscription, |
List<int> bufferedData, |
bool requestClientCertificate: false, |
- bool requireClientCertificate: false}) { |
+ bool requireClientCertificate: false, |
+ List<String> supportedProtocols}) { |
socket.readEventsEnabled = false; |
socket.writeEventsEnabled = false; |
return _RawSecureSocket.connect( |
@@ -353,7 +367,8 @@ abstract class RawSecureSocket implements RawSocket { |
subscription: subscription, |
bufferedData: bufferedData, |
requestClientCertificate: requestClientCertificate, |
- requireClientCertificate: requireClientCertificate); |
+ requireClientCertificate: requireClientCertificate, |
+ supportedProtocols: supportedProtocols); |
} |
/** |
@@ -375,6 +390,11 @@ abstract class RawSecureSocket implements RawSocket { |
* [peerCertificate] will return the server's certificate. |
*/ |
X509Certificate get peerCertificate; |
+ |
+ /** |
+ * Get the protocol which was selected during protocol negotiation. |
+ */ |
+ String get selectedProtocol; |
} |
@@ -459,6 +479,7 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
_SecureFilter _secureFilter = new _SecureFilter(); |
int _filterPointer; |
+ String _selectedProtocol; |
static Future<_RawSecureSocket> connect( |
host, |
@@ -471,7 +492,8 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
bool requestClientCertificate: false, |
bool requireClientCertificate: false, |
bool sendClientCertificate: false, |
- bool onBadCertificate(X509Certificate certificate)}) { |
+ bool onBadCertificate(X509Certificate certificate), |
+ List<String> supportedProtocols}) { |
_verifyFields(host, requestedPort, certificateName, is_server, |
requestClientCertificate, requireClientCertificate, |
sendClientCertificate, onBadCertificate); |
@@ -488,7 +510,8 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
requestClientCertificate, |
requireClientCertificate, |
sendClientCertificate, |
- onBadCertificate) |
+ onBadCertificate, |
+ supportedProtocols) |
._handshakeComplete.future; |
} |
@@ -503,7 +526,8 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
this.requestClientCertificate, |
this.requireClientCertificate, |
this.sendClientCertificate, |
- this.onBadCertificate(X509Certificate certificate)) { |
+ this.onBadCertificate(X509Certificate certificate), |
+ List<String> supportedProtocols) { |
_controller = new StreamController<RawSocketEvent>( |
sync: true, |
onListen: _onSubscriptionStateChange, |
@@ -548,13 +572,44 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
requestClientCertificate || |
requireClientCertificate, |
requireClientCertificate, |
- sendClientCertificate); |
+ sendClientCertificate, |
+ _protocolsToLengthEncoding(supportedProtocols)); |
_secureHandshake(); |
} catch (e, s) { |
_reportError(e, s); |
} |
} |
+ Uint8List _protocolsToLengthEncoding(List<String> protocols) { |
+ if (protocols == null || protocols.length == 0) { |
+ return new Uint8List(0); |
+ } |
+ |
+ // NOTE: The NSS library will treat the first protocol as the fallback |
+ // protocol. The remaining ones are sorted in priority order. |
+ // We therefore put the protocol least desired at the front, to make it the |
+ // default. |
+ List<int> bytes = []; |
Søren Gjesse
2014/10/03 15:47:04
You could allocate a 255 byte Uint8List here and r
kustermann
2014/11/07 16:20:03
Did something similar. Had some discussions with L
|
+ _addProtocolBytes(bytes, protocols.last); |
+ for (var i = 0; i < protocols.length -1; i++) { |
+ _addProtocolBytes(bytes, protocols[i]); |
+ } |
+ |
+ return new Uint8List.fromList(bytes); |
+ } |
+ |
+ void _addProtocolBytes(List<int> outBytes, String protocol) { |
+ var protocolBytes = UTF8.encode(protocol); |
+ var len = protocolBytes.length; |
+ |
+ if (len > 255) { |
+ throw new ArgumentError( |
+ 'Cannot support protocols with more than 255 characters'); |
+ } |
+ outBytes.add(len); |
+ outBytes.addAll(protocolBytes); |
+ } |
+ |
StreamSubscription listen(void onData(RawSocketEvent data), |
{Function onError, |
void onDone(), |
@@ -732,6 +787,8 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
X509Certificate get peerCertificate => _secureFilter.peerCertificate; |
+ String get selectedProtocol => _selectedProtocol; |
+ |
bool _onBadCertificateWrapper(X509Certificate certificate) { |
if (onBadCertificate == null) return false; |
var result = onBadCertificate(certificate); |
@@ -845,8 +902,13 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
_status = CONNECTED; |
if (_connectPending) { |
_connectPending = false; |
- // We don't want user code to run synchronously in this callback. |
- Timer.run(() => _handshakeComplete.complete(this)); |
+ try { |
+ _selectedProtocol = _secureFilter.selectedProtocol(); |
+ // We don't want user code to run synchronously in this callback. |
+ Timer.run(() => _handshakeComplete.complete(this)); |
+ } catch (error, stack) { |
+ _handshakeComplete.completeError(error, stack); |
+ } |
} |
} |
@@ -905,7 +967,7 @@ class _RawSecureSocket extends Stream<RawSocketEvent> |
_secureFilter.handshake(); |
if (_status == HANDSHAKE) { |
throw new HandshakeException( |
- 'Connection terminated during handshake'); |
+ 'xConnection terminated during handshake'); |
Søren Gjesse
2014/10/03 15:47:04
Accidental edit.
kustermann
2014/11/07 16:20:03
Done.
|
} |
} |
_closeHandler(); |
@@ -1206,7 +1268,8 @@ abstract class _SecureFilter { |
String certificateName, |
bool requestClientCertificate, |
bool requireClientCertificate, |
- bool sendClientCertificate); |
+ bool sendClientCertificate, |
+ Uint8List protocols); |
void destroy(); |
void handshake(); |
void rehandshake(); |