OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 /** | 7 /** |
8 * A high-level class for communicating securely over a TCP socket, using | 8 * A high-level class for communicating securely over a TCP socket, using |
9 * TLS and SSL. The [SecureSocket] exposes both a [Stream] and an | 9 * TLS and SSL. The [SecureSocket] exposes both a [Stream] and an |
10 * [IOSink] interface, making it ideal for using together with | 10 * [IOSink] interface, making it ideal for using together with |
(...skipping 11 matching lines...) Expand all Loading... |
22 * using the trusted certificates set in the SecurityContext object. | 22 * using the trusted certificates set in the SecurityContext object. |
23 * The default SecurityContext object contains a built-in set of trusted | 23 * The default SecurityContext object contains a built-in set of trusted |
24 * root certificates for well-known certificate authorities. | 24 * root certificates for well-known certificate authorities. |
25 * | 25 * |
26 * [onBadCertificate] is an optional handler for unverifiable certificates. | 26 * [onBadCertificate] is an optional handler for unverifiable certificates. |
27 * The handler receives the [X509Certificate], and can inspect it and | 27 * The handler receives the [X509Certificate], and can inspect it and |
28 * decide (or let the user decide) whether to accept | 28 * decide (or let the user decide) whether to accept |
29 * the connection or not. The handler should return true | 29 * the connection or not. The handler should return true |
30 * to continue the [SecureSocket] connection. | 30 * to continue the [SecureSocket] connection. |
31 */ | 31 */ |
32 static Future<SecureSocket> connect( | 32 static Future<SecureSocket> connect(host, int port, |
33 host, | |
34 int port, | |
35 {SecurityContext context, | 33 {SecurityContext context, |
36 bool onBadCertificate(X509Certificate certificate), | 34 bool onBadCertificate(X509Certificate certificate), |
37 List<String> supportedProtocols}) { | 35 List<String> supportedProtocols}) { |
38 return RawSecureSocket.connect(host, | 36 return RawSecureSocket |
39 port, | 37 .connect(host, port, |
40 context: context, | 38 context: context, |
41 onBadCertificate: onBadCertificate, | 39 onBadCertificate: onBadCertificate, |
42 supportedProtocols: supportedProtocols) | 40 supportedProtocols: supportedProtocols) |
43 .then((rawSocket) => new SecureSocket._(rawSocket)); | 41 .then((rawSocket) => new SecureSocket._(rawSocket)); |
44 } | 42 } |
45 | 43 |
46 /** | 44 /** |
47 * Takes an already connected [socket] and starts client side TLS | 45 * Takes an already connected [socket] and starts client side TLS |
48 * handshake to make the communication secure. When the returned | 46 * handshake to make the communication secure. When the returned |
49 * future completes the [SecureSocket] has completed the TLS | 47 * future completes the [SecureSocket] has completed the TLS |
50 * handshake. Using this function requires that the other end of the | 48 * handshake. Using this function requires that the other end of the |
51 * connection is prepared for TLS handshake. | 49 * connection is prepared for TLS handshake. |
52 * | 50 * |
53 * If the [socket] already has a subscription, this subscription | 51 * If the [socket] already has a subscription, this subscription |
54 * will no longer receive and events. In most cases calling | 52 * will no longer receive and events. In most cases calling |
55 * `pause` on this subscription before starting TLS handshake is | 53 * `pause` on this subscription before starting TLS handshake is |
56 * the right thing to do. | 54 * the right thing to do. |
57 * | 55 * |
58 * If the [host] argument is passed it will be used as the host name | 56 * If the [host] argument is passed it will be used as the host name |
59 * for the TLS handshake. If [host] is not passed the host name from | 57 * for the TLS handshake. If [host] is not passed the host name from |
60 * the [socket] will be used. The [host] can be either a [String] or | 58 * the [socket] will be used. The [host] can be either a [String] or |
61 * an [InternetAddress]. | 59 * an [InternetAddress]. |
62 * | 60 * |
63 * Calling this function will _not_ cause a DNS host lookup. If the | 61 * Calling this function will _not_ cause a DNS host lookup. If the |
64 * [host] passed is a [String] the [InternetAddress] for the | 62 * [host] passed is a [String] the [InternetAddress] for the |
65 * resulting [SecureSocket] will have the passed in [host] as its | 63 * resulting [SecureSocket] will have the passed in [host] as its |
66 * host value and the internet address of the already connected | 64 * host value and the internet address of the already connected |
67 * socket as its address value. | 65 * socket as its address value. |
68 * | 66 * |
69 * See [connect] for more information on the arguments. | 67 * See [connect] for more information on the arguments. |
70 * | 68 * |
71 */ | 69 */ |
72 static Future<SecureSocket> secure( | 70 static Future<SecureSocket> secure(Socket socket, |
73 Socket socket, | |
74 {host, | 71 {host, |
75 SecurityContext context, | 72 SecurityContext context, |
76 bool onBadCertificate(X509Certificate certificate)}) { | 73 bool onBadCertificate(X509Certificate certificate)}) { |
77 return ((socket as dynamic/*_Socket*/)._detachRaw() as Future) | 74 return ((socket as dynamic /*_Socket*/)._detachRaw() as Future) |
78 .then<RawSecureSocket>((detachedRaw) { | 75 .then<RawSecureSocket>((detachedRaw) { |
79 return RawSecureSocket.secure( | 76 return RawSecureSocket.secure(detachedRaw[0] as RawSocket, |
80 detachedRaw[0] as RawSocket, | 77 subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>, |
81 subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>, | 78 host: host, |
82 host: host, | 79 context: context, |
83 context: context, | 80 onBadCertificate: onBadCertificate); |
84 onBadCertificate: onBadCertificate); | 81 }).then<SecureSocket>((raw) => new SecureSocket._(raw)); |
85 }) | 82 } |
86 .then<SecureSocket>((raw) => new SecureSocket._(raw)); | |
87 } | |
88 | 83 |
89 /** | 84 /** |
90 * Takes an already connected [socket] and starts server side TLS | 85 * Takes an already connected [socket] and starts server side TLS |
91 * handshake to make the communication secure. When the returned | 86 * handshake to make the communication secure. When the returned |
92 * future completes the [SecureSocket] has completed the TLS | 87 * future completes the [SecureSocket] has completed the TLS |
93 * handshake. Using this function requires that the other end of the | 88 * handshake. Using this function requires that the other end of the |
94 * connection is going to start the TLS handshake. | 89 * connection is going to start the TLS handshake. |
95 * | 90 * |
96 * If the [socket] already has a subscription, this subscription | 91 * If the [socket] already has a subscription, this subscription |
97 * will no longer receive and events. In most cases calling | 92 * will no longer receive and events. In most cases calling |
98 * [:pause:] on this subscription before starting TLS handshake is | 93 * [:pause:] on this subscription before starting TLS handshake is |
99 * the right thing to do. | 94 * the right thing to do. |
100 * | 95 * |
101 * If some of the data of the TLS handshake has already been read | 96 * If some of the data of the TLS handshake has already been read |
102 * from the socket this data can be passed in the [bufferedData] | 97 * from the socket this data can be passed in the [bufferedData] |
103 * parameter. This data will be processed before any other data | 98 * parameter. This data will be processed before any other data |
104 * available on the socket. | 99 * available on the socket. |
105 * | 100 * |
106 * See [SecureServerSocket.bind] for more information on the | 101 * See [SecureServerSocket.bind] for more information on the |
107 * arguments. | 102 * arguments. |
108 * | 103 * |
109 */ | 104 */ |
110 static Future<SecureSocket> secureServer( | 105 static Future<SecureSocket> secureServer( |
111 Socket socket, | 106 Socket socket, SecurityContext context, |
112 SecurityContext context, | |
113 {List<int> bufferedData, | 107 {List<int> bufferedData, |
114 bool requestClientCertificate: false, | 108 bool requestClientCertificate: false, |
115 bool requireClientCertificate: false, | 109 bool requireClientCertificate: false, |
116 List<String> supportedProtocols}) { | 110 List<String> supportedProtocols}) { |
117 return ((socket as dynamic/*_Socket*/)._detachRaw() as Future) | 111 return ((socket as dynamic /*_Socket*/)._detachRaw() as Future) |
118 .then<RawSecureSocket>((detachedRaw) { | 112 .then<RawSecureSocket>((detachedRaw) { |
119 return RawSecureSocket.secureServer( | 113 return RawSecureSocket.secureServer(detachedRaw[0] as RawSocket, context, |
120 detachedRaw[0] as RawSocket, | 114 subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>, |
121 context, | 115 bufferedData: bufferedData, |
122 subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>, | 116 requestClientCertificate: requestClientCertificate, |
123 bufferedData: bufferedData, | 117 requireClientCertificate: requireClientCertificate, |
124 requestClientCertificate: requestClientCertificate, | 118 supportedProtocols: supportedProtocols); |
125 requireClientCertificate: requireClientCertificate, | 119 }).then<SecureSocket>((raw) => new SecureSocket._(raw)); |
126 supportedProtocols: supportedProtocols); | |
127 }) | |
128 .then<SecureSocket>((raw) => new SecureSocket._(raw)); | |
129 } | 120 } |
130 | 121 |
131 /** | 122 /** |
132 * Get the peer certificate for a connected SecureSocket. If this | 123 * Get the peer certificate for a connected SecureSocket. If this |
133 * SecureSocket is the server end of a secure socket connection, | 124 * SecureSocket is the server end of a secure socket connection, |
134 * [peerCertificate] will return the client certificate, or null, if no | 125 * [peerCertificate] will return the client certificate, or null, if no |
135 * client certificate was received. If it is the client end, | 126 * client certificate was received. If it is the client end, |
136 * [peerCertificate] will return the server's certificate. | 127 * [peerCertificate] will return the server's certificate. |
137 */ | 128 */ |
138 X509Certificate get peerCertificate; | 129 X509Certificate get peerCertificate; |
139 | 130 |
140 /** | 131 /** |
141 * Get the protocol which was selected during protocol negotiation. | 132 * Get the protocol which was selected during protocol negotiation. |
142 */ | 133 */ |
143 String get selectedProtocol; | 134 String get selectedProtocol; |
144 | 135 |
145 /** | 136 /** |
146 * Renegotiate an existing secure connection, renewing the session keys | 137 * Renegotiate an existing secure connection, renewing the session keys |
147 * and possibly changing the connection properties. | 138 * and possibly changing the connection properties. |
148 * | 139 * |
149 * This repeats the SSL or TLS handshake, with options that allow clearing | 140 * This repeats the SSL or TLS handshake, with options that allow clearing |
150 * the session cache and requesting a client certificate. | 141 * the session cache and requesting a client certificate. |
151 */ | 142 */ |
152 void renegotiate({bool useSessionCache: true, | 143 void renegotiate( |
153 bool requestClientCertificate: false, | 144 {bool useSessionCache: true, |
154 bool requireClientCertificate: false}); | 145 bool requestClientCertificate: false, |
| 146 bool requireClientCertificate: false}); |
155 } | 147 } |
156 | 148 |
157 | |
158 /** | 149 /** |
159 * RawSecureSocket provides a secure (SSL or TLS) network connection. | 150 * RawSecureSocket provides a secure (SSL or TLS) network connection. |
160 * Client connections to a server are provided by calling | 151 * Client connections to a server are provided by calling |
161 * RawSecureSocket.connect. A secure server, created with | 152 * RawSecureSocket.connect. A secure server, created with |
162 * [RawSecureServerSocket], also returns RawSecureSocket objects representing | 153 * [RawSecureServerSocket], also returns RawSecureSocket objects representing |
163 * the server end of a secure connection. | 154 * the server end of a secure connection. |
164 * The certificate provided by the server is checked | 155 * The certificate provided by the server is checked |
165 * using the trusted certificates set in the SecurityContext object. | 156 * using the trusted certificates set in the SecurityContext object. |
166 * The default [SecurityContext] object contains a built-in set of trusted | 157 * The default [SecurityContext] object contains a built-in set of trusted |
167 * root certificates for well-known certificate authorities. | 158 * root certificates for well-known certificate authorities. |
168 */ | 159 */ |
169 abstract class RawSecureSocket implements RawSocket { | 160 abstract class RawSecureSocket implements RawSocket { |
170 /** | 161 /** |
171 * Constructs a new secure client socket and connect it to the given | 162 * Constructs a new secure client socket and connect it to the given |
172 * host on the given port. The returned [Future] is completed with the | 163 * host on the given port. The returned [Future] is completed with the |
173 * RawSecureSocket when it is connected and ready for subscription. | 164 * RawSecureSocket when it is connected and ready for subscription. |
174 * | 165 * |
175 * The certificate provided by the server is checked using the trusted | 166 * The certificate provided by the server is checked using the trusted |
176 * certificates set in the SecurityContext object If a certificate and key are | 167 * certificates set in the SecurityContext object If a certificate and key are |
177 * set on the client, using [SecurityContext.useCertificateChain] and | 168 * set on the client, using [SecurityContext.useCertificateChain] and |
178 * [SecurityContext.usePrivateKey], and the server asks for a client | 169 * [SecurityContext.usePrivateKey], and the server asks for a client |
179 * certificate, then that client certificate is sent to the server. | 170 * certificate, then that client certificate is sent to the server. |
180 * | 171 * |
181 * [onBadCertificate] is an optional handler for unverifiable certificates. | 172 * [onBadCertificate] is an optional handler for unverifiable certificates. |
182 * The handler receives the [X509Certificate], and can inspect it and | 173 * The handler receives the [X509Certificate], and can inspect it and |
183 * decide (or let the user decide) whether to accept | 174 * decide (or let the user decide) whether to accept |
184 * the connection or not. The handler should return true | 175 * the connection or not. The handler should return true |
185 * to continue the [RawSecureSocket] connection. | 176 * to continue the [RawSecureSocket] connection. |
186 */ | 177 */ |
187 static Future<RawSecureSocket> connect( | 178 static Future<RawSecureSocket> connect(host, int port, |
188 host, | |
189 int port, | |
190 {SecurityContext context, | 179 {SecurityContext context, |
191 bool onBadCertificate(X509Certificate certificate), | 180 bool onBadCertificate(X509Certificate certificate), |
192 List<String> supportedProtocols}) { | 181 List<String> supportedProtocols}) { |
193 _RawSecureSocket._verifyFields( | 182 _RawSecureSocket._verifyFields( |
194 host, | 183 host, port, false, false, false, onBadCertificate); |
195 port, | 184 return RawSocket.connect(host, port).then((socket) { |
196 false, | 185 return secure(socket, |
197 false, | 186 context: context, |
198 false, | 187 onBadCertificate: onBadCertificate, |
199 onBadCertificate); | 188 supportedProtocols: supportedProtocols); |
200 return RawSocket.connect(host, port) | 189 }); |
201 .then((socket) { | |
202 return secure(socket, | |
203 context: context, | |
204 onBadCertificate: onBadCertificate, | |
205 supportedProtocols: supportedProtocols); | |
206 }); | |
207 } | 190 } |
208 | 191 |
209 /** | 192 /** |
210 * Takes an already connected [socket] and starts client side TLS | 193 * Takes an already connected [socket] and starts client side TLS |
211 * handshake to make the communication secure. When the returned | 194 * handshake to make the communication secure. When the returned |
212 * future completes the [RawSecureSocket] has completed the TLS | 195 * future completes the [RawSecureSocket] has completed the TLS |
213 * handshake. Using this function requires that the other end of the | 196 * handshake. Using this function requires that the other end of the |
214 * connection is prepared for TLS handshake. | 197 * connection is prepared for TLS handshake. |
215 * | 198 * |
216 * If the [socket] already has a subscription, pass the existing | 199 * If the [socket] already has a subscription, pass the existing |
(...skipping 10 matching lines...) Expand all Loading... |
227 * | 210 * |
228 * Calling this function will _not_ cause a DNS host lookup. If the | 211 * Calling this function will _not_ cause a DNS host lookup. If the |
229 * [host] passed is a [String] the [InternetAddress] for the | 212 * [host] passed is a [String] the [InternetAddress] for the |
230 * resulting [SecureSocket] will have this passed in [host] as its | 213 * resulting [SecureSocket] will have this passed in [host] as its |
231 * host value and the internet address of the already connected | 214 * host value and the internet address of the already connected |
232 * socket as its address value. | 215 * socket as its address value. |
233 * | 216 * |
234 * See [connect] for more information on the arguments. | 217 * See [connect] for more information on the arguments. |
235 * | 218 * |
236 */ | 219 */ |
237 static Future<RawSecureSocket> secure( | 220 static Future<RawSecureSocket> secure(RawSocket socket, |
238 RawSocket socket, | |
239 {StreamSubscription<RawSocketEvent> subscription, | 221 {StreamSubscription<RawSocketEvent> subscription, |
240 host, | 222 host, |
241 SecurityContext context, | 223 SecurityContext context, |
242 bool onBadCertificate(X509Certificate certificate), | 224 bool onBadCertificate(X509Certificate certificate), |
243 List<String> supportedProtocols}) { | 225 List<String> supportedProtocols}) { |
244 socket.readEventsEnabled = false; | 226 socket.readEventsEnabled = false; |
245 socket.writeEventsEnabled = false; | 227 socket.writeEventsEnabled = false; |
246 return _RawSecureSocket.connect( | 228 return _RawSecureSocket.connect( |
247 host != null ? host : socket.address.host, | 229 host != null ? host : socket.address.host, socket.port, |
248 socket.port, | |
249 is_server: false, | 230 is_server: false, |
250 socket: socket, | 231 socket: socket, |
251 subscription: subscription, | 232 subscription: subscription, |
252 context: context, | 233 context: context, |
253 onBadCertificate: onBadCertificate, | 234 onBadCertificate: onBadCertificate, |
254 supportedProtocols: supportedProtocols); | 235 supportedProtocols: supportedProtocols); |
255 } | 236 } |
256 | 237 |
257 /** | 238 /** |
258 * Takes an already connected [socket] and starts server side TLS | 239 * Takes an already connected [socket] and starts server side TLS |
(...skipping 12 matching lines...) Expand all Loading... |
271 * If some of the data of the TLS handshake has already been read | 252 * If some of the data of the TLS handshake has already been read |
272 * from the socket this data can be passed in the [bufferedData] | 253 * from the socket this data can be passed in the [bufferedData] |
273 * parameter. This data will be processed before any other data | 254 * parameter. This data will be processed before any other data |
274 * available on the socket. | 255 * available on the socket. |
275 * | 256 * |
276 * See [RawSecureServerSocket.bind] for more information on the | 257 * See [RawSecureServerSocket.bind] for more information on the |
277 * arguments. | 258 * arguments. |
278 * | 259 * |
279 */ | 260 */ |
280 static Future<RawSecureSocket> secureServer( | 261 static Future<RawSecureSocket> secureServer( |
281 RawSocket socket, | 262 RawSocket socket, SecurityContext context, |
282 SecurityContext context, | |
283 {StreamSubscription<RawSocketEvent> subscription, | 263 {StreamSubscription<RawSocketEvent> subscription, |
284 List<int> bufferedData, | 264 List<int> bufferedData, |
285 bool requestClientCertificate: false, | 265 bool requestClientCertificate: false, |
286 bool requireClientCertificate: false, | 266 bool requireClientCertificate: false, |
287 List<String> supportedProtocols}) { | 267 List<String> supportedProtocols}) { |
288 socket.readEventsEnabled = false; | 268 socket.readEventsEnabled = false; |
289 socket.writeEventsEnabled = false; | 269 socket.writeEventsEnabled = false; |
290 return _RawSecureSocket.connect( | 270 return _RawSecureSocket.connect(socket.address, socket.remotePort, |
291 socket.address, | |
292 socket.remotePort, | |
293 context: context, | 271 context: context, |
294 is_server: true, | 272 is_server: true, |
295 socket: socket, | 273 socket: socket, |
296 subscription: subscription, | 274 subscription: subscription, |
297 bufferedData: bufferedData, | 275 bufferedData: bufferedData, |
298 requestClientCertificate: requestClientCertificate, | 276 requestClientCertificate: requestClientCertificate, |
299 requireClientCertificate: requireClientCertificate, | 277 requireClientCertificate: requireClientCertificate, |
300 supportedProtocols: supportedProtocols); | 278 supportedProtocols: supportedProtocols); |
301 } | 279 } |
302 | 280 |
303 /** | 281 /** |
304 * Renegotiate an existing secure connection, renewing the session keys | 282 * Renegotiate an existing secure connection, renewing the session keys |
305 * and possibly changing the connection properties. | 283 * and possibly changing the connection properties. |
306 * | 284 * |
307 * This repeats the SSL or TLS handshake, with options that allow clearing | 285 * This repeats the SSL or TLS handshake, with options that allow clearing |
308 * the session cache and requesting a client certificate. | 286 * the session cache and requesting a client certificate. |
309 */ | 287 */ |
310 void renegotiate({bool useSessionCache: true, | 288 void renegotiate( |
311 bool requestClientCertificate: false, | 289 {bool useSessionCache: true, |
312 bool requireClientCertificate: false}); | 290 bool requestClientCertificate: false, |
| 291 bool requireClientCertificate: false}); |
313 | 292 |
314 /** | 293 /** |
315 * Get the peer certificate for a connected RawSecureSocket. If this | 294 * Get the peer certificate for a connected RawSecureSocket. If this |
316 * RawSecureSocket is the server end of a secure socket connection, | 295 * RawSecureSocket is the server end of a secure socket connection, |
317 * [peerCertificate] will return the client certificate, or null, if no | 296 * [peerCertificate] will return the client certificate, or null, if no |
318 * client certificate was received. If it is the client end, | 297 * client certificate was received. If it is the client end, |
319 * [peerCertificate] will return the server's certificate. | 298 * [peerCertificate] will return the server's certificate. |
320 */ | 299 */ |
321 X509Certificate get peerCertificate; | 300 X509Certificate get peerCertificate; |
322 | 301 |
323 /** | 302 /** |
324 * Get the protocol which was selected during protocol negotiation. | 303 * Get the protocol which was selected during protocol negotiation. |
325 */ | 304 */ |
326 String get selectedProtocol; | 305 String get selectedProtocol; |
327 } | 306 } |
328 | 307 |
329 | |
330 /** | 308 /** |
331 * X509Certificate represents an SSL certificate, with accessors to | 309 * X509Certificate represents an SSL certificate, with accessors to |
332 * get the fields of the certificate. | 310 * get the fields of the certificate. |
333 */ | 311 */ |
334 abstract class X509Certificate { | 312 abstract class X509Certificate { |
335 external factory X509Certificate._(); | 313 external factory X509Certificate._(); |
336 | 314 |
337 String get subject; | 315 String get subject; |
338 String get issuer; | 316 String get issuer; |
339 DateTime get startValidity; | 317 DateTime get startValidity; |
340 DateTime get endValidity; | 318 DateTime get endValidity; |
341 } | 319 } |
342 | 320 |
343 | |
344 class _FilterStatus { | 321 class _FilterStatus { |
345 bool progress = false; // The filter read or wrote data to the buffers. | 322 bool progress = false; // The filter read or wrote data to the buffers. |
346 bool readEmpty = true; // The read buffers and decryption filter are empty. | 323 bool readEmpty = true; // The read buffers and decryption filter are empty. |
347 bool writeEmpty = true; // The write buffers and encryption filter are empty. | 324 bool writeEmpty = true; // The write buffers and encryption filter are empty. |
348 // These are set if a buffer changes state from empty or full. | 325 // These are set if a buffer changes state from empty or full. |
349 bool readPlaintextNoLongerEmpty = false; | 326 bool readPlaintextNoLongerEmpty = false; |
350 bool writePlaintextNoLongerFull = false; | 327 bool writePlaintextNoLongerFull = false; |
351 bool readEncryptedNoLongerFull = false; | 328 bool readEncryptedNoLongerFull = false; |
352 bool writeEncryptedNoLongerEmpty = false; | 329 bool writeEncryptedNoLongerEmpty = false; |
353 | 330 |
354 _FilterStatus(); | 331 _FilterStatus(); |
355 } | 332 } |
356 | 333 |
357 | |
358 class _RawSecureSocket extends Stream<RawSocketEvent> | 334 class _RawSecureSocket extends Stream<RawSocketEvent> |
359 implements RawSecureSocket { | 335 implements RawSecureSocket { |
360 // Status states | 336 // Status states |
361 static final int HANDSHAKE = 201; | 337 static final int HANDSHAKE = 201; |
362 static final int CONNECTED = 202; | 338 static final int CONNECTED = 202; |
363 static final int CLOSED = 203; | 339 static final int CLOSED = 203; |
364 | 340 |
365 // Buffer identifiers. | 341 // Buffer identifiers. |
366 // These must agree with those in the native C++ implementation. | 342 // These must agree with those in the native C++ implementation. |
367 static final int READ_PLAINTEXT = 0; | 343 static final int READ_PLAINTEXT = 0; |
368 static final int WRITE_PLAINTEXT = 1; | 344 static final int WRITE_PLAINTEXT = 1; |
369 static final int READ_ENCRYPTED = 2; | 345 static final int READ_ENCRYPTED = 2; |
370 static final int WRITE_ENCRYPTED = 3; | 346 static final int WRITE_ENCRYPTED = 3; |
371 static final int NUM_BUFFERS = 4; | 347 static final int NUM_BUFFERS = 4; |
372 | 348 |
373 // Is a buffer identifier for an encrypted buffer? | 349 // Is a buffer identifier for an encrypted buffer? |
374 static bool _isBufferEncrypted(int identifier) => identifier >= READ_ENCRYPTED
; | 350 static bool _isBufferEncrypted(int identifier) => |
| 351 identifier >= READ_ENCRYPTED; |
375 | 352 |
376 RawSocket _socket; | 353 RawSocket _socket; |
377 final Completer<_RawSecureSocket> _handshakeComplete = | 354 final Completer<_RawSecureSocket> _handshakeComplete = |
378 new Completer<_RawSecureSocket>(); | 355 new Completer<_RawSecureSocket>(); |
379 StreamController<RawSocketEvent> _controller; | 356 StreamController<RawSocketEvent> _controller; |
380 Stream<RawSocketEvent> _stream; | 357 Stream<RawSocketEvent> _stream; |
381 StreamSubscription<RawSocketEvent> _socketSubscription; | 358 StreamSubscription<RawSocketEvent> _socketSubscription; |
382 List<int> _bufferedData; | 359 List<int> _bufferedData; |
383 int _bufferedDataIndex = 0; | 360 int _bufferedDataIndex = 0; |
384 final InternetAddress address; | 361 final InternetAddress address; |
385 final bool is_server; | 362 final bool is_server; |
386 SecurityContext context; | 363 SecurityContext context; |
387 final bool requestClientCertificate; | 364 final bool requestClientCertificate; |
388 final bool requireClientCertificate; | 365 final bool requireClientCertificate; |
389 final Function onBadCertificate; | 366 final Function onBadCertificate; |
390 | 367 |
391 var _status = HANDSHAKE; | 368 var _status = HANDSHAKE; |
392 bool _writeEventsEnabled = true; | 369 bool _writeEventsEnabled = true; |
393 bool _readEventsEnabled = true; | 370 bool _readEventsEnabled = true; |
394 int _pauseCount = 0; | 371 int _pauseCount = 0; |
395 bool _pendingReadEvent = false; | 372 bool _pendingReadEvent = false; |
396 bool _socketClosedRead = false; // The network socket is closed for reading. | 373 bool _socketClosedRead = false; // The network socket is closed for reading. |
397 bool _socketClosedWrite = false; // The network socket is closed for writing. | 374 bool _socketClosedWrite = false; // The network socket is closed for writing. |
398 bool _closedRead = false; // The secure socket has fired an onClosed event. | 375 bool _closedRead = false; // The secure socket has fired an onClosed event. |
399 bool _closedWrite = false; // The secure socket has been closed for writing. | 376 bool _closedWrite = false; // The secure socket has been closed for writing. |
400 // The network socket is gone. | 377 // The network socket is gone. |
401 Completer<RawSecureSocket> _closeCompleter = new Completer<RawSecureSocket>(); | 378 Completer<RawSecureSocket> _closeCompleter = new Completer<RawSecureSocket>(); |
402 _FilterStatus _filterStatus = new _FilterStatus(); | 379 _FilterStatus _filterStatus = new _FilterStatus(); |
403 bool _connectPending = true; | 380 bool _connectPending = true; |
404 bool _filterPending = false; | 381 bool _filterPending = false; |
405 bool _filterActive = false; | 382 bool _filterActive = false; |
406 | 383 |
407 _SecureFilter _secureFilter = new _SecureFilter(); | 384 _SecureFilter _secureFilter = new _SecureFilter(); |
408 String _selectedProtocol; | 385 String _selectedProtocol; |
409 | 386 |
410 static Future<_RawSecureSocket> connect( | 387 static Future<_RawSecureSocket> connect( |
411 dynamic/*String|InternetAddress*/ host, | 388 dynamic /*String|InternetAddress*/ host, int requestedPort, |
412 int requestedPort, | |
413 {bool is_server, | 389 {bool is_server, |
414 SecurityContext context, | 390 SecurityContext context, |
415 RawSocket socket, | 391 RawSocket socket, |
416 StreamSubscription<RawSocketEvent> subscription, | 392 StreamSubscription<RawSocketEvent> subscription, |
417 List<int> bufferedData, | 393 List<int> bufferedData, |
418 bool requestClientCertificate: false, | 394 bool requestClientCertificate: false, |
419 bool requireClientCertificate: false, | 395 bool requireClientCertificate: false, |
420 bool onBadCertificate(X509Certificate certificate), | 396 bool onBadCertificate(X509Certificate certificate), |
421 List<String> supportedProtocols}) { | 397 List<String> supportedProtocols}) { |
422 _verifyFields(host, requestedPort, is_server, | 398 _verifyFields(host, requestedPort, is_server, requestClientCertificate, |
423 requestClientCertificate, requireClientCertificate, | 399 requireClientCertificate, onBadCertificate); |
424 onBadCertificate); | |
425 if (host is InternetAddress) host = host.host; | 400 if (host is InternetAddress) host = host.host; |
426 InternetAddress address = socket.address; | 401 InternetAddress address = socket.address; |
427 if (host != null) { | 402 if (host != null) { |
428 address = InternetAddress._cloneWithNewHost(address, host); | 403 address = InternetAddress._cloneWithNewHost(address, host); |
429 } | 404 } |
430 return new _RawSecureSocket(address, | 405 return new _RawSecureSocket( |
431 requestedPort, | 406 address, |
432 is_server, | 407 requestedPort, |
433 context, | 408 is_server, |
434 socket, | 409 context, |
435 subscription, | 410 socket, |
436 bufferedData, | 411 subscription, |
437 requestClientCertificate, | 412 bufferedData, |
438 requireClientCertificate, | 413 requestClientCertificate, |
439 onBadCertificate, | 414 requireClientCertificate, |
440 supportedProtocols) | 415 onBadCertificate, |
441 ._handshakeComplete.future; | 416 supportedProtocols) |
| 417 ._handshakeComplete |
| 418 .future; |
442 } | 419 } |
443 | 420 |
444 _RawSecureSocket( | 421 _RawSecureSocket( |
445 this.address, | 422 this.address, |
446 int requestedPort, | 423 int requestedPort, |
447 this.is_server, | 424 this.is_server, |
448 this.context, | 425 this.context, |
449 this._socket, | 426 this._socket, |
450 this._socketSubscription, | 427 this._socketSubscription, |
451 this._bufferedData, | 428 this._bufferedData, |
452 this.requestClientCertificate, | 429 this.requestClientCertificate, |
453 this.requireClientCertificate, | 430 this.requireClientCertificate, |
454 this.onBadCertificate, | 431 this.onBadCertificate, |
455 List<String> supportedProtocols) { | 432 List<String> supportedProtocols) { |
456 if (context == null) { | 433 if (context == null) { |
457 context = SecurityContext.defaultContext; | 434 context = SecurityContext.defaultContext; |
458 } | 435 } |
459 _controller = new StreamController<RawSocketEvent>( | 436 _controller = new StreamController<RawSocketEvent>( |
460 sync: true, | 437 sync: true, |
461 onListen: _onSubscriptionStateChange, | 438 onListen: _onSubscriptionStateChange, |
462 onPause: _onPauseStateChange, | 439 onPause: _onPauseStateChange, |
463 onResume: _onPauseStateChange, | 440 onResume: _onPauseStateChange, |
464 onCancel: _onSubscriptionStateChange); | 441 onCancel: _onSubscriptionStateChange); |
465 _stream = _controller.stream; | 442 _stream = _controller.stream; |
466 // Throw an ArgumentError if any field is invalid. After this, all | 443 // Throw an ArgumentError if any field is invalid. After this, all |
467 // errors will be reported through the future or the stream. | 444 // errors will be reported through the future or the stream. |
468 _secureFilter.init(); | 445 _secureFilter.init(); |
469 _secureFilter.registerHandshakeCompleteCallback( | 446 _secureFilter |
470 _secureHandshakeCompleteHandler); | 447 .registerHandshakeCompleteCallback(_secureHandshakeCompleteHandler); |
471 if (onBadCertificate != null) { | 448 if (onBadCertificate != null) { |
472 _secureFilter.registerBadCertificateCallback(_onBadCertificateWrapper); | 449 _secureFilter.registerBadCertificateCallback(_onBadCertificateWrapper); |
473 } | 450 } |
474 _socket.readEventsEnabled = true; | 451 _socket.readEventsEnabled = true; |
475 _socket.writeEventsEnabled = false; | 452 _socket.writeEventsEnabled = false; |
476 if (_socketSubscription == null) { | 453 if (_socketSubscription == null) { |
477 // If a current subscription is provided use this otherwise | 454 // If a current subscription is provided use this otherwise |
478 // create a new one. | 455 // create a new one. |
479 _socketSubscription = _socket.listen(_eventDispatcher, | 456 _socketSubscription = _socket.listen(_eventDispatcher, |
480 onError: _reportError, | 457 onError: _reportError, onDone: _doneHandler); |
481 onDone: _doneHandler); | |
482 } else { | 458 } else { |
483 if (_socketSubscription.isPaused) { | 459 if (_socketSubscription.isPaused) { |
484 _socket.close(); | 460 _socket.close(); |
485 throw new ArgumentError( | 461 throw new ArgumentError("Subscription passed to TLS upgrade is paused"); |
486 "Subscription passed to TLS upgrade is paused"); | |
487 } | 462 } |
488 // If we are upgrading a socket that is already closed for read, | 463 // If we are upgrading a socket that is already closed for read, |
489 // report an error as if we received READ_CLOSED during the handshake. | 464 // report an error as if we received READ_CLOSED during the handshake. |
490 dynamic s = _socket; // Cast to dynamic to avoid warning. | 465 dynamic s = _socket; // Cast to dynamic to avoid warning. |
491 if (s._socket.closedReadEventSent) { | 466 if (s._socket.closedReadEventSent) { |
492 _eventDispatcher(RawSocketEvent.READ_CLOSED); | 467 _eventDispatcher(RawSocketEvent.READ_CLOSED); |
493 } | 468 } |
494 _socketSubscription | 469 _socketSubscription |
495 ..onData(_eventDispatcher) | 470 ..onData(_eventDispatcher) |
496 ..onError(_reportError) | 471 ..onError(_reportError) |
497 ..onDone(_doneHandler); | 472 ..onDone(_doneHandler); |
498 } | 473 } |
499 try { | 474 try { |
500 var encodedProtocols = | 475 var encodedProtocols = |
501 SecurityContext._protocolsToLengthEncoding(supportedProtocols); | 476 SecurityContext._protocolsToLengthEncoding(supportedProtocols); |
502 _secureFilter.connect(address.host, | 477 _secureFilter.connect( |
503 context, | 478 address.host, |
504 is_server, | 479 context, |
505 requestClientCertificate || | 480 is_server, |
506 requireClientCertificate, | 481 requestClientCertificate || requireClientCertificate, |
507 requireClientCertificate, | 482 requireClientCertificate, |
508 encodedProtocols); | 483 encodedProtocols); |
509 _secureHandshake(); | 484 _secureHandshake(); |
510 } catch (e, s) { | 485 } catch (e, s) { |
511 _reportError(e, s); | 486 _reportError(e, s); |
512 } | 487 } |
513 } | 488 } |
514 | 489 |
515 StreamSubscription<RawSocketEvent> listen(void onData(RawSocketEvent data), | 490 StreamSubscription<RawSocketEvent> listen(void onData(RawSocketEvent data), |
516 {Function onError, | 491 {Function onError, void onDone(), bool cancelOnError}) { |
517 void onDone(), | |
518 bool cancelOnError}) { | |
519 _sendWriteEvent(); | 492 _sendWriteEvent(); |
520 return _stream.listen(onData, | 493 return _stream.listen(onData, |
521 onError: onError, | 494 onError: onError, onDone: onDone, cancelOnError: cancelOnError); |
522 onDone: onDone, | |
523 cancelOnError: cancelOnError); | |
524 } | 495 } |
525 | 496 |
526 static void _verifyFields(host, | 497 static void _verifyFields( |
527 int requestedPort, | 498 host, |
528 bool is_server, | 499 int requestedPort, |
529 bool requestClientCertificate, | 500 bool is_server, |
530 bool requireClientCertificate, | 501 bool requestClientCertificate, |
531 Function onBadCertificate) { | 502 bool requireClientCertificate, |
| 503 Function onBadCertificate) { |
532 if (host is! String && host is! InternetAddress) { | 504 if (host is! String && host is! InternetAddress) { |
533 throw new ArgumentError("host is not a String or an InternetAddress"); | 505 throw new ArgumentError("host is not a String or an InternetAddress"); |
534 } | 506 } |
535 if (requestedPort is! int) { | 507 if (requestedPort is! int) { |
536 throw new ArgumentError("requestedPort is not an int"); | 508 throw new ArgumentError("requestedPort is not an int"); |
537 } | 509 } |
538 if (requestedPort < 0 || requestedPort > 65535) { | 510 if (requestedPort < 0 || requestedPort > 65535) { |
539 throw new ArgumentError("requestedPort is not in the range 0..65535"); | 511 throw new ArgumentError("requestedPort is not in the range 0..65535"); |
540 } | 512 } |
541 if (requestClientCertificate is! bool) { | 513 if (requestClientCertificate is! bool) { |
542 throw new ArgumentError("requestClientCertificate is not a bool"); | 514 throw new ArgumentError("requestClientCertificate is not a bool"); |
543 } | 515 } |
544 if (requireClientCertificate is! bool) { | 516 if (requireClientCertificate is! bool) { |
545 throw new ArgumentError("requireClientCertificate is not a bool"); | 517 throw new ArgumentError("requireClientCertificate is not a bool"); |
546 } | 518 } |
547 if (onBadCertificate != null && onBadCertificate is! Function) { | 519 if (onBadCertificate != null && onBadCertificate is! Function) { |
548 throw new ArgumentError("onBadCertificate is not null or a Function"); | 520 throw new ArgumentError("onBadCertificate is not null or a Function"); |
549 } | 521 } |
550 } | 522 } |
551 | 523 |
552 int get port => _socket.port; | 524 int get port => _socket.port; |
553 | 525 |
554 InternetAddress get remoteAddress => _socket.remoteAddress; | 526 InternetAddress get remoteAddress => _socket.remoteAddress; |
555 | 527 |
556 int get remotePort => _socket.remotePort; | 528 int get remotePort => _socket.remotePort; |
557 | 529 |
558 void set _owner(owner) { | 530 void set _owner(owner) { |
559 (_socket as dynamic)._owner = owner; | 531 (_socket as dynamic)._owner = owner; |
560 } | 532 } |
561 | 533 |
562 int available() { | 534 int available() { |
563 return _status != CONNECTED ? 0 | 535 return _status != CONNECTED |
564 : _secureFilter.buffers[READ_PLAINTEXT].length; | 536 ? 0 |
| 537 : _secureFilter.buffers[READ_PLAINTEXT].length; |
565 } | 538 } |
566 | 539 |
567 Future<RawSecureSocket> close() { | 540 Future<RawSecureSocket> close() { |
568 shutdown(SocketDirection.BOTH); | 541 shutdown(SocketDirection.BOTH); |
569 return _closeCompleter.future; | 542 return _closeCompleter.future; |
570 } | 543 } |
571 | 544 |
572 void _completeCloseCompleter([RawSocket dummy]) { | 545 void _completeCloseCompleter([RawSocket dummy]) { |
573 if (!_closeCompleter.isCompleted) _closeCompleter.complete(this); | 546 if (!_closeCompleter.isCompleted) _closeCompleter.complete(this); |
574 } | 547 } |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
622 void set writeEventsEnabled(bool value) { | 595 void set writeEventsEnabled(bool value) { |
623 _writeEventsEnabled = value; | 596 _writeEventsEnabled = value; |
624 if (value) { | 597 if (value) { |
625 Timer.run(() => _sendWriteEvent()); | 598 Timer.run(() => _sendWriteEvent()); |
626 } | 599 } |
627 } | 600 } |
628 | 601 |
629 bool get readEventsEnabled => _readEventsEnabled; | 602 bool get readEventsEnabled => _readEventsEnabled; |
630 | 603 |
631 void set readEventsEnabled(bool value) { | 604 void set readEventsEnabled(bool value) { |
632 _readEventsEnabled = value; | 605 _readEventsEnabled = value; |
633 _scheduleReadEvent(); | 606 _scheduleReadEvent(); |
634 } | 607 } |
635 | 608 |
636 List<int> read([int length]) { | 609 List<int> read([int length]) { |
637 if (length != null && (length is! int || length < 0)) { | 610 if (length != null && (length is! int || length < 0)) { |
638 throw new ArgumentError( | 611 throw new ArgumentError( |
639 "Invalid length parameter in SecureSocket.read (length: $length)"); | 612 "Invalid length parameter in SecureSocket.read (length: $length)"); |
640 } | 613 } |
641 if (_closedRead) { | 614 if (_closedRead) { |
642 throw new SocketException("Reading from a closed socket"); | 615 throw new SocketException("Reading from a closed socket"); |
643 } | 616 } |
644 if (_status != CONNECTED) { | 617 if (_status != CONNECTED) { |
645 return null; | 618 return null; |
646 } | 619 } |
647 var result = _secureFilter.buffers[READ_PLAINTEXT].read(length); | 620 var result = _secureFilter.buffers[READ_PLAINTEXT].read(length); |
648 _scheduleFilter(); | 621 _scheduleFilter(); |
649 return result; | 622 return result; |
650 } | 623 } |
651 | 624 |
652 // Write the data to the socket, and schedule the filter to encrypt it. | 625 // Write the data to the socket, and schedule the filter to encrypt it. |
653 int write(List<int> data, [int offset, int bytes]) { | 626 int write(List<int> data, [int offset, int bytes]) { |
654 if (bytes != null && (bytes is! int || bytes < 0)) { | 627 if (bytes != null && (bytes is! int || bytes < 0)) { |
655 throw new ArgumentError( | 628 throw new ArgumentError( |
656 "Invalid bytes parameter in SecureSocket.read (bytes: $bytes)"); | 629 "Invalid bytes parameter in SecureSocket.read (bytes: $bytes)"); |
657 } | 630 } |
658 if (offset != null && (offset is! int || offset < 0)) { | 631 if (offset != null && (offset is! int || offset < 0)) { |
659 throw new ArgumentError( | 632 throw new ArgumentError( |
660 "Invalid offset parameter in SecureSocket.read (offset: $offset)"); | 633 "Invalid offset parameter in SecureSocket.read (offset: $offset)"); |
661 } | 634 } |
662 if (_closedWrite) { | 635 if (_closedWrite) { |
663 _controller.addError(new SocketException("Writing to a closed socket")); | 636 _controller.addError(new SocketException("Writing to a closed socket")); |
664 return 0; | 637 return 0; |
665 } | 638 } |
666 if (_status != CONNECTED) return 0; | 639 if (_status != CONNECTED) return 0; |
667 if (offset == null) offset = 0; | 640 if (offset == null) offset = 0; |
668 if (bytes == null) bytes = data.length - offset; | 641 if (bytes == null) bytes = data.length - offset; |
669 | 642 |
670 int written = | 643 int written = |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
731 // _handshakeComplete future returned from SecureSocket.connect has | 704 // _handshakeComplete future returned from SecureSocket.connect has |
732 // completed. Before this point, we must complete it with an error. | 705 // completed. Before this point, we must complete it with an error. |
733 _handshakeComplete.completeError(e, stackTrace); | 706 _handshakeComplete.completeError(e, stackTrace); |
734 } else { | 707 } else { |
735 _controller.addError(e, stackTrace); | 708 _controller.addError(e, stackTrace); |
736 } | 709 } |
737 _close(); | 710 _close(); |
738 } | 711 } |
739 | 712 |
740 void _closeHandler() { | 713 void _closeHandler() { |
741 if (_status == CONNECTED) { | 714 if (_status == CONNECTED) { |
742 if (_closedRead) return; | 715 if (_closedRead) return; |
743 _socketClosedRead = true; | 716 _socketClosedRead = true; |
744 if (_filterStatus.readEmpty) { | 717 if (_filterStatus.readEmpty) { |
745 _closedRead = true; | 718 _closedRead = true; |
746 _controller.add(RawSocketEvent.READ_CLOSED); | 719 _controller.add(RawSocketEvent.READ_CLOSED); |
747 if (_socketClosedWrite) { | 720 if (_socketClosedWrite) { |
748 _close(); | 721 _close(); |
749 } | 722 } |
750 } else { | 723 } else { |
751 _scheduleFilter(); | 724 _scheduleFilter(); |
752 } | 725 } |
753 } else if (_status == HANDSHAKE) { | 726 } else if (_status == HANDSHAKE) { |
754 _socketClosedRead = true; | 727 _socketClosedRead = true; |
755 if (_filterStatus.readEmpty) { | 728 if (_filterStatus.readEmpty) { |
756 _reportError( | 729 _reportError( |
757 new HandshakeException('Connection terminated during handshake'), | 730 new HandshakeException('Connection terminated during handshake'), |
758 null); | 731 null); |
759 } else { | 732 } else { |
760 _secureHandshake(); | 733 _secureHandshake(); |
761 } | 734 } |
762 } | 735 } |
763 } | 736 } |
764 | 737 |
765 void _secureHandshake() { | 738 void _secureHandshake() { |
766 try { | 739 try { |
767 _secureFilter.handshake(); | 740 _secureFilter.handshake(); |
768 _filterStatus.writeEmpty = false; | 741 _filterStatus.writeEmpty = false; |
769 _readSocket(); | 742 _readSocket(); |
770 _writeSocket(); | 743 _writeSocket(); |
771 _scheduleFilter(); | 744 _scheduleFilter(); |
772 } catch (e, stackTrace) { | 745 } catch (e, stackTrace) { |
773 _reportError(e, stackTrace); | 746 _reportError(e, stackTrace); |
774 } | 747 } |
775 } | 748 } |
776 | 749 |
777 void renegotiate({bool useSessionCache: true, | 750 void renegotiate( |
778 bool requestClientCertificate: false, | 751 {bool useSessionCache: true, |
779 bool requireClientCertificate: false}) { | 752 bool requestClientCertificate: false, |
| 753 bool requireClientCertificate: false}) { |
780 if (_status != CONNECTED) { | 754 if (_status != CONNECTED) { |
781 throw new HandshakeException( | 755 throw new HandshakeException( |
782 "Called renegotiate on a non-connected socket"); | 756 "Called renegotiate on a non-connected socket"); |
783 } | 757 } |
784 _secureFilter.renegotiate(useSessionCache, | 758 _secureFilter.renegotiate( |
785 requestClientCertificate, | 759 useSessionCache, requestClientCertificate, requireClientCertificate); |
786 requireClientCertificate); | |
787 _status = HANDSHAKE; | 760 _status = HANDSHAKE; |
788 _filterStatus.writeEmpty = false; | 761 _filterStatus.writeEmpty = false; |
789 _scheduleFilter(); | 762 _scheduleFilter(); |
790 } | 763 } |
791 | 764 |
792 void _secureHandshakeCompleteHandler() { | 765 void _secureHandshakeCompleteHandler() { |
793 _status = CONNECTED; | 766 _status = CONNECTED; |
794 if (_connectPending) { | 767 if (_connectPending) { |
795 _connectPending = false; | 768 _connectPending = false; |
796 try { | 769 try { |
797 _selectedProtocol = _secureFilter.selectedProtocol(); | 770 _selectedProtocol = _secureFilter.selectedProtocol(); |
798 // We don't want user code to run synchronously in this callback. | 771 // We don't want user code to run synchronously in this callback. |
799 Timer.run(() => _handshakeComplete.complete(this)); | 772 Timer.run(() => _handshakeComplete.complete(this)); |
800 } catch (error, stack) { | 773 } catch (error, stack) { |
801 _handshakeComplete.completeError(error, stack); | 774 _handshakeComplete.completeError(error, stack); |
802 } | 775 } |
803 } | 776 } |
804 } | 777 } |
805 | 778 |
806 void _onPauseStateChange() { | 779 void _onPauseStateChange() { |
807 if (_controller.isPaused) { | 780 if (_controller.isPaused) { |
808 _pauseCount++; | 781 _pauseCount++; |
809 } else { | 782 } else { |
810 _pauseCount--; | 783 _pauseCount--; |
811 if (_pauseCount == 0) { | 784 if (_pauseCount == 0) { |
812 _scheduleReadEvent(); | 785 _scheduleReadEvent(); |
813 _sendWriteEvent(); // Can send event synchronously. | 786 _sendWriteEvent(); // Can send event synchronously. |
814 } | 787 } |
815 } | 788 } |
816 | 789 |
817 if (!_socketClosedRead || !_socketClosedWrite) { | 790 if (!_socketClosedRead || !_socketClosedWrite) { |
818 if (_controller.isPaused) { | 791 if (_controller.isPaused) { |
819 _socketSubscription.pause(); | 792 _socketSubscription.pause(); |
820 } else { | 793 } else { |
821 _socketSubscription.resume(); | 794 _socketSubscription.resume(); |
822 } | 795 } |
823 } | 796 } |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
891 _tryFilter(); | 864 _tryFilter(); |
892 }).catchError(_reportError); | 865 }).catchError(_reportError); |
893 } | 866 } |
894 } | 867 } |
895 | 868 |
896 List<int> _readSocketOrBufferedData(int bytes) { | 869 List<int> _readSocketOrBufferedData(int bytes) { |
897 if (_bufferedData != null) { | 870 if (_bufferedData != null) { |
898 if (bytes > _bufferedData.length - _bufferedDataIndex) { | 871 if (bytes > _bufferedData.length - _bufferedDataIndex) { |
899 bytes = _bufferedData.length - _bufferedDataIndex; | 872 bytes = _bufferedData.length - _bufferedDataIndex; |
900 } | 873 } |
901 var result = _bufferedData.sublist(_bufferedDataIndex, | 874 var result = |
902 _bufferedDataIndex + bytes); | 875 _bufferedData.sublist(_bufferedDataIndex, _bufferedDataIndex + bytes); |
903 _bufferedDataIndex += bytes; | 876 _bufferedDataIndex += bytes; |
904 if (_bufferedData.length == _bufferedDataIndex) { | 877 if (_bufferedData.length == _bufferedDataIndex) { |
905 _bufferedData = null; | 878 _bufferedData = null; |
906 } | 879 } |
907 return result; | 880 return result; |
908 } else if (!_socketClosedRead) { | 881 } else if (!_socketClosedRead) { |
909 return _socket.read(bytes); | 882 return _socket.read(bytes); |
910 } else { | 883 } else { |
911 return null; | 884 return null; |
912 } | 885 } |
913 } | 886 } |
914 | 887 |
915 void _readSocket() { | 888 void _readSocket() { |
916 if (_status == CLOSED) return; | 889 if (_status == CLOSED) return; |
917 var buffer = _secureFilter.buffers[READ_ENCRYPTED]; | 890 var buffer = _secureFilter.buffers[READ_ENCRYPTED]; |
918 if (buffer.writeFromSource(_readSocketOrBufferedData) > 0) { | 891 if (buffer.writeFromSource(_readSocketOrBufferedData) > 0) { |
919 _filterStatus.readEmpty = false; | 892 _filterStatus.readEmpty = false; |
920 } else { | 893 } else { |
921 _socket.readEventsEnabled = false; | 894 _socket.readEventsEnabled = false; |
922 } | 895 } |
923 } | 896 } |
924 | 897 |
925 void _writeSocket() { | 898 void _writeSocket() { |
926 if (_socketClosedWrite) return; | 899 if (_socketClosedWrite) return; |
927 var buffer = _secureFilter.buffers[WRITE_ENCRYPTED]; | 900 var buffer = _secureFilter.buffers[WRITE_ENCRYPTED]; |
928 if (buffer.readToSocket(_socket)) { // Returns true if blocked | 901 if (buffer.readToSocket(_socket)) { |
| 902 // Returns true if blocked |
929 _socket.writeEventsEnabled = true; | 903 _socket.writeEventsEnabled = true; |
930 } | 904 } |
931 } | 905 } |
932 | 906 |
933 // If a read event should be sent, add it to the controller. | 907 // If a read event should be sent, add it to the controller. |
934 _scheduleReadEvent() { | 908 _scheduleReadEvent() { |
935 if (!_pendingReadEvent && | 909 if (!_pendingReadEvent && |
936 _readEventsEnabled && | 910 _readEventsEnabled && |
937 _pauseCount == 0 && | 911 _pauseCount == 0 && |
938 _secureFilter != null && | 912 _secureFilter != null && |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
979 | 953 |
980 return _IOService._dispatch(_SSL_PROCESS_FILTER, args).then((response) { | 954 return _IOService._dispatch(_SSL_PROCESS_FILTER, args).then((response) { |
981 if (response.length == 2) { | 955 if (response.length == 2) { |
982 if (wasInHandshake) { | 956 if (wasInHandshake) { |
983 // If we're in handshake, throw a handshake error. | 957 // If we're in handshake, throw a handshake error. |
984 _reportError( | 958 _reportError( |
985 new HandshakeException('${response[1]} error ${response[0]}'), | 959 new HandshakeException('${response[1]} error ${response[0]}'), |
986 null); | 960 null); |
987 } else { | 961 } else { |
988 // If we're connected, throw a TLS error. | 962 // If we're connected, throw a TLS error. |
989 _reportError(new TlsException('${response[1]} error ${response[0]}'), | 963 _reportError( |
990 null); | 964 new TlsException('${response[1]} error ${response[0]}'), null); |
991 } | 965 } |
992 } | 966 } |
993 int start(int index) => response[2 * index]; | 967 int start(int index) => response[2 * index]; |
994 int end(int index) => response[2 * index + 1]; | 968 int end(int index) => response[2 * index + 1]; |
995 | 969 |
996 _FilterStatus status = new _FilterStatus(); | 970 _FilterStatus status = new _FilterStatus(); |
997 // Compute writeEmpty as "write plaintext buffer and write encrypted | 971 // Compute writeEmpty as "write plaintext buffer and write encrypted |
998 // buffer were empty when we started and are empty now". | 972 // buffer were empty when we started and are empty now". |
999 status.writeEmpty = bufs[WRITE_PLAINTEXT].isEmpty && | 973 status.writeEmpty = bufs[WRITE_PLAINTEXT].isEmpty && |
1000 start(WRITE_ENCRYPTED) == end(WRITE_ENCRYPTED); | 974 start(WRITE_ENCRYPTED) == end(WRITE_ENCRYPTED); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1041 if (buffer.length == 0) { | 1015 if (buffer.length == 0) { |
1042 status.readPlaintextNoLongerEmpty = true; | 1016 status.readPlaintextNoLongerEmpty = true; |
1043 } | 1017 } |
1044 buffer.end = new_end; | 1018 buffer.end = new_end; |
1045 } | 1019 } |
1046 return status; | 1020 return status; |
1047 }); | 1021 }); |
1048 } | 1022 } |
1049 } | 1023 } |
1050 | 1024 |
1051 | |
1052 /** | 1025 /** |
1053 * A circular buffer backed by an external byte array. Accessed from | 1026 * A circular buffer backed by an external byte array. Accessed from |
1054 * both C++ and Dart code in an unsynchronized way, with one reading | 1027 * both C++ and Dart code in an unsynchronized way, with one reading |
1055 * and one writing. All updates to start and end are done by Dart code. | 1028 * and one writing. All updates to start and end are done by Dart code. |
1056 */ | 1029 */ |
1057 class _ExternalBuffer { | 1030 class _ExternalBuffer { |
1058 // This will be an ExternalByteArray, backed by C allocated data. | 1031 // This will be an ExternalByteArray, backed by C allocated data. |
1059 List<int> data; | 1032 List<int> data; |
1060 int start; | 1033 int start; |
1061 int end; | 1034 int end; |
(...skipping 18 matching lines...) Expand all Loading... |
1080 end += bytes; | 1053 end += bytes; |
1081 if (end >= size) { | 1054 if (end >= size) { |
1082 end -= size; | 1055 end -= size; |
1083 assert(end < start); | 1056 assert(end < start); |
1084 assert(end < size); | 1057 assert(end < size); |
1085 } | 1058 } |
1086 } | 1059 } |
1087 | 1060 |
1088 bool get isEmpty => end == start; | 1061 bool get isEmpty => end == start; |
1089 | 1062 |
1090 int get length => | 1063 int get length => start > end ? size + end - start : end - start; |
1091 start > end ? size + end - start : end - start; | |
1092 | 1064 |
1093 int get linearLength => | 1065 int get linearLength => start > end ? size - start : end - start; |
1094 start > end ? size - start : end - start; | |
1095 | 1066 |
1096 int get free => | 1067 int get free => start > end ? start - end - 1 : size + start - end - 1; |
1097 start > end ? start - end - 1 : size + start - end - 1; | |
1098 | 1068 |
1099 int get linearFree { | 1069 int get linearFree { |
1100 if (start > end) return start - end - 1; | 1070 if (start > end) return start - end - 1; |
1101 if (start == 0) return size - end - 1; | 1071 if (start == 0) return size - end - 1; |
1102 return size - end; | 1072 return size - end; |
1103 } | 1073 } |
1104 | 1074 |
1105 List<int> read(int bytes) { | 1075 List<int> read(int bytes) { |
1106 if (bytes == null) { | 1076 if (bytes == null) { |
1107 bytes = length; | 1077 bytes = length; |
1108 } else { | 1078 } else { |
1109 bytes = min(bytes, length); | 1079 bytes = min(bytes, length); |
1110 } | 1080 } |
1111 if (bytes == 0) return null; | 1081 if (bytes == 0) return null; |
1112 List<int> result = new Uint8List(bytes); | 1082 List<int> result = new Uint8List(bytes); |
1113 int bytesRead = 0; | 1083 int bytesRead = 0; |
1114 // Loop over zero, one, or two linear data ranges. | 1084 // Loop over zero, one, or two linear data ranges. |
1115 while (bytesRead < bytes) { | 1085 while (bytesRead < bytes) { |
1116 int toRead = min(bytes - bytesRead, linearLength); | 1086 int toRead = min(bytes - bytesRead, linearLength); |
1117 result.setRange(bytesRead, | 1087 result.setRange(bytesRead, bytesRead + toRead, data, start); |
1118 bytesRead + toRead, | |
1119 data, | |
1120 start); | |
1121 advanceStart(toRead); | 1088 advanceStart(toRead); |
1122 bytesRead += toRead; | 1089 bytesRead += toRead; |
1123 } | 1090 } |
1124 return result; | 1091 return result; |
1125 } | 1092 } |
1126 | 1093 |
1127 int write(List<int> inputData, int offset, int bytes) { | 1094 int write(List<int> inputData, int offset, int bytes) { |
1128 if (bytes > free) { | 1095 if (bytes > free) { |
1129 bytes = free; | 1096 bytes = free; |
1130 } | 1097 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1166 int bytes = socket.write(data, start, toWrite); | 1133 int bytes = socket.write(data, start, toWrite); |
1167 advanceStart(bytes); | 1134 advanceStart(bytes); |
1168 if (bytes < toWrite) { | 1135 if (bytes < toWrite) { |
1169 // The socket has blocked while we have data to write. | 1136 // The socket has blocked while we have data to write. |
1170 return true; | 1137 return true; |
1171 } | 1138 } |
1172 } | 1139 } |
1173 } | 1140 } |
1174 } | 1141 } |
1175 | 1142 |
1176 | |
1177 abstract class _SecureFilter { | 1143 abstract class _SecureFilter { |
1178 external factory _SecureFilter(); | 1144 external factory _SecureFilter(); |
1179 | 1145 |
1180 void connect(String hostName, | 1146 void connect( |
1181 SecurityContext context, | 1147 String hostName, |
1182 bool is_server, | 1148 SecurityContext context, |
1183 bool requestClientCertificate, | 1149 bool is_server, |
1184 bool requireClientCertificate, | 1150 bool requestClientCertificate, |
1185 Uint8List protocols); | 1151 bool requireClientCertificate, |
| 1152 Uint8List protocols); |
1186 void destroy(); | 1153 void destroy(); |
1187 void handshake(); | 1154 void handshake(); |
1188 String selectedProtocol(); | 1155 String selectedProtocol(); |
1189 void rehandshake(); | 1156 void rehandshake(); |
1190 void renegotiate(bool useSessionCache, | 1157 void renegotiate(bool useSessionCache, bool requestClientCertificate, |
1191 bool requestClientCertificate, | 1158 bool requireClientCertificate); |
1192 bool requireClientCertificate); | |
1193 void init(); | 1159 void init(); |
1194 X509Certificate get peerCertificate; | 1160 X509Certificate get peerCertificate; |
1195 int processBuffer(int bufferIndex); | 1161 int processBuffer(int bufferIndex); |
1196 void registerBadCertificateCallback(Function callback); | 1162 void registerBadCertificateCallback(Function callback); |
1197 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler); | 1163 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler); |
1198 | 1164 |
1199 // This call may cause a reference counted pointer in the native | 1165 // This call may cause a reference counted pointer in the native |
1200 // implementation to be retained. It should only be called when the resulting | 1166 // implementation to be retained. It should only be called when the resulting |
1201 // value is passed to the IO service through a call to dispatch(). | 1167 // value is passed to the IO service through a call to dispatch(). |
1202 int _pointer(); | 1168 int _pointer(); |
1203 | 1169 |
1204 List<_ExternalBuffer> get buffers; | 1170 List<_ExternalBuffer> get buffers; |
1205 } | 1171 } |
1206 | 1172 |
1207 /** A secure networking exception caused by a failure in the | 1173 /** A secure networking exception caused by a failure in the |
1208 * TLS/SSL protocol. | 1174 * TLS/SSL protocol. |
1209 */ | 1175 */ |
1210 class TlsException implements IOException { | 1176 class TlsException implements IOException { |
1211 final String type; | 1177 final String type; |
1212 final String message; | 1178 final String message; |
1213 final OSError osError; | 1179 final OSError osError; |
1214 | 1180 |
1215 const TlsException([String message = "", | 1181 const TlsException([String message = "", OSError osError = null]) |
1216 OSError osError = null]) | 1182 : this._("TlsException", message, osError); |
1217 : this._("TlsException", message, osError); | |
1218 | 1183 |
1219 const TlsException._(this.type, this.message, this.osError); | 1184 const TlsException._(this.type, this.message, this.osError); |
1220 | 1185 |
1221 String toString() { | 1186 String toString() { |
1222 StringBuffer sb = new StringBuffer(); | 1187 StringBuffer sb = new StringBuffer(); |
1223 sb.write(type); | 1188 sb.write(type); |
1224 if (!message.isEmpty) { | 1189 if (!message.isEmpty) { |
1225 sb.write(": $message"); | 1190 sb.write(": $message"); |
1226 if (osError != null) { | 1191 if (osError != null) { |
1227 sb.write(" ($osError)"); | 1192 sb.write(" ($osError)"); |
1228 } | 1193 } |
1229 } else if (osError != null) { | 1194 } else if (osError != null) { |
1230 sb.write(": $osError"); | 1195 sb.write(": $osError"); |
1231 } | 1196 } |
1232 return sb.toString(); | 1197 return sb.toString(); |
1233 } | 1198 } |
1234 } | 1199 } |
1235 | 1200 |
1236 | |
1237 /** | 1201 /** |
1238 * An exception that happens in the handshake phase of establishing | 1202 * An exception that happens in the handshake phase of establishing |
1239 * a secure network connection. | 1203 * a secure network connection. |
1240 */ | 1204 */ |
1241 class HandshakeException extends TlsException { | 1205 class HandshakeException extends TlsException { |
1242 const HandshakeException([String message = "", | 1206 const HandshakeException([String message = "", OSError osError = null]) |
1243 OSError osError = null]) | 1207 : super._("HandshakeException", message, osError); |
1244 : super._("HandshakeException", message, osError); | |
1245 } | 1208 } |
1246 | 1209 |
1247 | |
1248 /** | 1210 /** |
1249 * An exception that happens in the handshake phase of establishing | 1211 * An exception that happens in the handshake phase of establishing |
1250 * a secure network connection, when looking up or verifying a | 1212 * a secure network connection, when looking up or verifying a |
1251 * certificate. | 1213 * certificate. |
1252 */ | 1214 */ |
1253 class CertificateException extends TlsException { | 1215 class CertificateException extends TlsException { |
1254 const CertificateException([String message = "", | 1216 const CertificateException([String message = "", OSError osError = null]) |
1255 OSError osError = null]) | 1217 : super._("CertificateException", message, osError); |
1256 : super._("CertificateException", message, osError); | |
1257 } | 1218 } |
OLD | NEW |