| 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 |