Chromium Code Reviews| 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 21 matching lines...) Expand all Loading... | |
| 32 * The handler receives the [X509Certificate], and can inspect it and | 32 * The handler receives the [X509Certificate], and can inspect it and |
| 33 * decide (or let the user decide) whether to accept | 33 * decide (or let the user decide) whether to accept |
| 34 * the connection or not. The handler should return true | 34 * the connection or not. The handler should return true |
| 35 * to continue the [SecureSocket] connection. | 35 * to continue the [SecureSocket] connection. |
| 36 */ | 36 */ |
| 37 static Future<SecureSocket> connect( | 37 static Future<SecureSocket> connect( |
| 38 host, | 38 host, |
| 39 int port, | 39 int port, |
| 40 {bool sendClientCertificate: false, | 40 {bool sendClientCertificate: false, |
| 41 String certificateName, | 41 String certificateName, |
| 42 bool onBadCertificate(X509Certificate certificate)}) { | 42 bool onBadCertificate(X509Certificate certificate), |
| 43 List<String> supportedProtocols}) { | |
| 43 return RawSecureSocket.connect(host, | 44 return RawSecureSocket.connect(host, |
| 44 port, | 45 port, |
| 45 sendClientCertificate: sendClientCertificate, | 46 sendClientCertificate: sendClientCertificate, |
| 46 certificateName: certificateName, | 47 certificateName: certificateName, |
| 47 onBadCertificate: onBadCertificate) | 48 onBadCertificate: onBadCertificate, |
| 49 supportedProtocols: supportedProtocols) | |
| 48 .then((rawSocket) => new SecureSocket._(rawSocket)); | 50 .then((rawSocket) => new SecureSocket._(rawSocket)); |
| 49 } | 51 } |
| 50 | 52 |
| 51 /** | 53 /** |
| 52 * Takes an already connected [socket] and starts client side TLS | 54 * Takes an already connected [socket] and starts client side TLS |
| 53 * handshake to make the communication secure. When the returned | 55 * handshake to make the communication secure. When the returned |
| 54 * future completes the [SecureSocket] has completed the TLS | 56 * future completes the [SecureSocket] has completed the TLS |
| 55 * handshake. Using this function requires that the other end of the | 57 * handshake. Using this function requires that the other end of the |
| 56 * connection is prepared for TLS handshake. | 58 * connection is prepared for TLS handshake. |
| 57 * | 59 * |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 115 * | 117 * |
| 116 * See [SecureServerSocket.bind] for more information on the | 118 * See [SecureServerSocket.bind] for more information on the |
| 117 * arguments. | 119 * arguments. |
| 118 * | 120 * |
| 119 */ | 121 */ |
| 120 static Future<SecureSocket> secureServer( | 122 static Future<SecureSocket> secureServer( |
| 121 Socket socket, | 123 Socket socket, |
| 122 String certificateName, | 124 String certificateName, |
| 123 {List<int> bufferedData, | 125 {List<int> bufferedData, |
| 124 bool requestClientCertificate: false, | 126 bool requestClientCertificate: false, |
| 125 bool requireClientCertificate: false}) { | 127 bool requireClientCertificate: false, |
| 128 List<String> supportedProtocols}) { | |
| 126 var completer = new Completer(); | 129 var completer = new Completer(); |
| 127 (socket as dynamic)._detachRaw() | 130 (socket as dynamic)._detachRaw() |
| 128 .then((detachedRaw) { | 131 .then((detachedRaw) { |
| 129 return RawSecureSocket.secureServer( | 132 return RawSecureSocket.secureServer( |
| 130 detachedRaw[0], | 133 detachedRaw[0], |
| 131 certificateName, | 134 certificateName, |
| 132 subscription: detachedRaw[1], | 135 subscription: detachedRaw[1], |
| 133 bufferedData: bufferedData, | 136 bufferedData: bufferedData, |
| 134 requestClientCertificate: requestClientCertificate, | 137 requestClientCertificate: requestClientCertificate, |
| 135 requireClientCertificate: requireClientCertificate); | 138 requireClientCertificate: requireClientCertificate, |
| 139 supportedProtocols: supportedProtocols); | |
| 136 }) | 140 }) |
| 137 .then((raw) { | 141 .then((raw) { |
| 138 completer.complete(new SecureSocket._(raw)); | 142 completer.complete(new SecureSocket._(raw)); |
| 139 }); | 143 }); |
| 140 return completer.future; | 144 return completer.future; |
| 141 } | 145 } |
| 142 | 146 |
| 143 /** | 147 /** |
| 144 * Get the peer certificate for a connected SecureSocket. If this | 148 * Get the peer certificate for a connected SecureSocket. If this |
| 145 * SecureSocket is the server end of a secure socket connection, | 149 * SecureSocket is the server end of a secure socket connection, |
| 146 * [peerCertificate] will return the client certificate, or null, if no | 150 * [peerCertificate] will return the client certificate, or null, if no |
| 147 * client certificate was received. If it is the client end, | 151 * client certificate was received. If it is the client end, |
| 148 * [peerCertificate] will return the server's certificate. | 152 * [peerCertificate] will return the server's certificate. |
| 149 */ | 153 */ |
| 150 X509Certificate get peerCertificate; | 154 X509Certificate get peerCertificate; |
| 151 | 155 |
| 152 /** | 156 /** |
| 157 * Get the protocol which was selected during protocol negotiation. | |
| 158 */ | |
| 159 String get selectedProtocol; | |
| 160 | |
| 161 /** | |
| 153 * Renegotiate an existing secure connection, renewing the session keys | 162 * Renegotiate an existing secure connection, renewing the session keys |
| 154 * and possibly changing the connection properties. | 163 * and possibly changing the connection properties. |
| 155 * | 164 * |
| 156 * This repeats the SSL or TLS handshake, with options that allow clearing | 165 * This repeats the SSL or TLS handshake, with options that allow clearing |
| 157 * the session cache and requesting a client certificate. | 166 * the session cache and requesting a client certificate. |
| 158 */ | 167 */ |
| 159 void renegotiate({bool useSessionCache: true, | 168 void renegotiate({bool useSessionCache: true, |
| 160 bool requestClientCertificate: false, | 169 bool requestClientCertificate: false, |
| 161 bool requireClientCertificate: false}); | 170 bool requireClientCertificate: false}); |
| 162 | 171 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 * The handler receives the [X509Certificate], and can inspect it and | 247 * The handler receives the [X509Certificate], and can inspect it and |
| 239 * decide (or let the user decide) whether to accept | 248 * decide (or let the user decide) whether to accept |
| 240 * the connection or not. The handler should return true | 249 * the connection or not. The handler should return true |
| 241 * to continue the [RawSecureSocket] connection. | 250 * to continue the [RawSecureSocket] connection. |
| 242 */ | 251 */ |
| 243 static Future<RawSecureSocket> connect( | 252 static Future<RawSecureSocket> connect( |
| 244 host, | 253 host, |
| 245 int port, | 254 int port, |
| 246 {bool sendClientCertificate: false, | 255 {bool sendClientCertificate: false, |
| 247 String certificateName, | 256 String certificateName, |
| 248 bool onBadCertificate(X509Certificate certificate)}) { | 257 bool onBadCertificate(X509Certificate certificate), |
| 258 List<String> supportedProtocols}) { | |
| 249 _RawSecureSocket._verifyFields( | 259 _RawSecureSocket._verifyFields( |
| 250 host, | 260 host, |
| 251 port, | 261 port, |
| 252 certificateName, | 262 certificateName, |
| 253 false, | 263 false, |
| 254 false, | 264 false, |
| 255 false, | 265 false, |
| 256 sendClientCertificate, | 266 sendClientCertificate, |
| 257 onBadCertificate); | 267 onBadCertificate); |
| 258 return RawSocket.connect(host, port) | 268 return RawSocket.connect(host, port) |
| 259 .then((socket) { | 269 .then((socket) { |
| 260 return secure(socket, | 270 return secure(socket, |
| 261 sendClientCertificate: sendClientCertificate, | 271 sendClientCertificate: sendClientCertificate, |
| 262 certificateName: certificateName, | 272 certificateName: certificateName, |
| 263 onBadCertificate: onBadCertificate); | 273 onBadCertificate: onBadCertificate, |
| 274 supportedProtocols: supportedProtocols); | |
| 264 }); | 275 }); |
| 265 } | 276 } |
| 266 | 277 |
| 267 /** | 278 /** |
| 268 * Takes an already connected [socket] and starts client side TLS | 279 * Takes an already connected [socket] and starts client side TLS |
| 269 * handshake to make the communication secure. When the returned | 280 * handshake to make the communication secure. When the returned |
| 270 * future completes the [RawSecureSocket] has completed the TLS | 281 * future completes the [RawSecureSocket] has completed the TLS |
| 271 * handshake. Using this function requires that the other end of the | 282 * handshake. Using this function requires that the other end of the |
| 272 * connection is prepared for TLS handshake. | 283 * connection is prepared for TLS handshake. |
| 273 * | 284 * |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 291 * | 302 * |
| 292 * See [connect] for more information on the arguments. | 303 * See [connect] for more information on the arguments. |
| 293 * | 304 * |
| 294 */ | 305 */ |
| 295 static Future<RawSecureSocket> secure( | 306 static Future<RawSecureSocket> secure( |
| 296 RawSocket socket, | 307 RawSocket socket, |
| 297 {StreamSubscription subscription, | 308 {StreamSubscription subscription, |
| 298 host, | 309 host, |
| 299 bool sendClientCertificate: false, | 310 bool sendClientCertificate: false, |
| 300 String certificateName, | 311 String certificateName, |
| 301 bool onBadCertificate(X509Certificate certificate)}) { | 312 bool onBadCertificate(X509Certificate certificate), |
| 313 List<String> supportedProtocols}) { | |
| 302 socket.readEventsEnabled = false; | 314 socket.readEventsEnabled = false; |
| 303 socket.writeEventsEnabled = false; | 315 socket.writeEventsEnabled = false; |
| 304 return _RawSecureSocket.connect( | 316 return _RawSecureSocket.connect( |
| 305 host != null ? host : socket.address.host, | 317 host != null ? host : socket.address.host, |
| 306 socket.port, | 318 socket.port, |
| 307 certificateName, | 319 certificateName, |
| 308 is_server: false, | 320 is_server: false, |
| 309 socket: socket, | 321 socket: socket, |
| 310 subscription: subscription, | 322 subscription: subscription, |
| 311 sendClientCertificate: sendClientCertificate, | 323 sendClientCertificate: sendClientCertificate, |
| 312 onBadCertificate: onBadCertificate); | 324 onBadCertificate: onBadCertificate, |
| 325 supportedProtocols: supportedProtocols); | |
| 313 } | 326 } |
| 314 | 327 |
| 315 /** | 328 /** |
| 316 * Takes an already connected [socket] and starts server side TLS | 329 * Takes an already connected [socket] and starts server side TLS |
| 317 * handshake to make the communication secure. When the returned | 330 * handshake to make the communication secure. When the returned |
| 318 * future completes the [RawSecureSocket] has completed the TLS | 331 * future completes the [RawSecureSocket] has completed the TLS |
| 319 * handshake. Using this function requires that the other end of the | 332 * handshake. Using this function requires that the other end of the |
| 320 * connection is going to start the TLS handshake. | 333 * connection is going to start the TLS handshake. |
| 321 * | 334 * |
| 322 * If the [socket] already has a subscription, pass the existing | 335 * If the [socket] already has a subscription, pass the existing |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 334 * See [RawSecureServerSocket.bind] for more information on the | 347 * See [RawSecureServerSocket.bind] for more information on the |
| 335 * arguments. | 348 * arguments. |
| 336 * | 349 * |
| 337 */ | 350 */ |
| 338 static Future<RawSecureSocket> secureServer( | 351 static Future<RawSecureSocket> secureServer( |
| 339 RawSocket socket, | 352 RawSocket socket, |
| 340 String certificateName, | 353 String certificateName, |
| 341 {StreamSubscription subscription, | 354 {StreamSubscription subscription, |
| 342 List<int> bufferedData, | 355 List<int> bufferedData, |
| 343 bool requestClientCertificate: false, | 356 bool requestClientCertificate: false, |
| 344 bool requireClientCertificate: false}) { | 357 bool requireClientCertificate: false, |
| 358 List<String> supportedProtocols}) { | |
| 345 socket.readEventsEnabled = false; | 359 socket.readEventsEnabled = false; |
| 346 socket.writeEventsEnabled = false; | 360 socket.writeEventsEnabled = false; |
| 347 return _RawSecureSocket.connect( | 361 return _RawSecureSocket.connect( |
| 348 socket.address, | 362 socket.address, |
| 349 socket.remotePort, | 363 socket.remotePort, |
| 350 certificateName, | 364 certificateName, |
| 351 is_server: true, | 365 is_server: true, |
| 352 socket: socket, | 366 socket: socket, |
| 353 subscription: subscription, | 367 subscription: subscription, |
| 354 bufferedData: bufferedData, | 368 bufferedData: bufferedData, |
| 355 requestClientCertificate: requestClientCertificate, | 369 requestClientCertificate: requestClientCertificate, |
| 356 requireClientCertificate: requireClientCertificate); | 370 requireClientCertificate: requireClientCertificate, |
| 371 supportedProtocols: supportedProtocols); | |
| 357 } | 372 } |
| 358 | 373 |
| 359 /** | 374 /** |
| 360 * Renegotiate an existing secure connection, renewing the session keys | 375 * Renegotiate an existing secure connection, renewing the session keys |
| 361 * and possibly changing the connection properties. | 376 * and possibly changing the connection properties. |
| 362 * | 377 * |
| 363 * This repeats the SSL or TLS handshake, with options that allow clearing | 378 * This repeats the SSL or TLS handshake, with options that allow clearing |
| 364 * the session cache and requesting a client certificate. | 379 * the session cache and requesting a client certificate. |
| 365 */ | 380 */ |
| 366 void renegotiate({bool useSessionCache: true, | 381 void renegotiate({bool useSessionCache: true, |
| 367 bool requestClientCertificate: false, | 382 bool requestClientCertificate: false, |
| 368 bool requireClientCertificate: false}); | 383 bool requireClientCertificate: false}); |
| 369 | 384 |
| 370 /** | 385 /** |
| 371 * Get the peer certificate for a connected RawSecureSocket. If this | 386 * Get the peer certificate for a connected RawSecureSocket. If this |
| 372 * RawSecureSocket is the server end of a secure socket connection, | 387 * RawSecureSocket is the server end of a secure socket connection, |
| 373 * [peerCertificate] will return the client certificate, or null, if no | 388 * [peerCertificate] will return the client certificate, or null, if no |
| 374 * client certificate was received. If it is the client end, | 389 * client certificate was received. If it is the client end, |
| 375 * [peerCertificate] will return the server's certificate. | 390 * [peerCertificate] will return the server's certificate. |
| 376 */ | 391 */ |
| 377 X509Certificate get peerCertificate; | 392 X509Certificate get peerCertificate; |
| 393 | |
| 394 /** | |
| 395 * Get the protocol which was selected during protocol negotiation. | |
| 396 */ | |
| 397 String get selectedProtocol; | |
| 378 } | 398 } |
| 379 | 399 |
| 380 | 400 |
| 381 /** | 401 /** |
| 382 * X509Certificate represents an SSL certificate, with accessors to | 402 * X509Certificate represents an SSL certificate, with accessors to |
| 383 * get the fields of the certificate. | 403 * get the fields of the certificate. |
| 384 */ | 404 */ |
| 385 class X509Certificate { | 405 class X509Certificate { |
| 386 X509Certificate(this.subject, | 406 X509Certificate(this.subject, |
| 387 this.issuer, | 407 this.issuer, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 452 bool _closedRead = false; // The secure socket has fired an onClosed event. | 472 bool _closedRead = false; // The secure socket has fired an onClosed event. |
| 453 bool _closedWrite = false; // The secure socket has been closed for writing. | 473 bool _closedWrite = false; // The secure socket has been closed for writing. |
| 454 Completer _closeCompleter = new Completer(); // The network socket is gone. | 474 Completer _closeCompleter = new Completer(); // The network socket is gone. |
| 455 _FilterStatus _filterStatus = new _FilterStatus(); | 475 _FilterStatus _filterStatus = new _FilterStatus(); |
| 456 bool _connectPending = true; | 476 bool _connectPending = true; |
| 457 bool _filterPending = false; | 477 bool _filterPending = false; |
| 458 bool _filterActive = false; | 478 bool _filterActive = false; |
| 459 | 479 |
| 460 _SecureFilter _secureFilter = new _SecureFilter(); | 480 _SecureFilter _secureFilter = new _SecureFilter(); |
| 461 int _filterPointer; | 481 int _filterPointer; |
| 482 String _selectedProtocol; | |
| 462 | 483 |
| 463 static Future<_RawSecureSocket> connect( | 484 static Future<_RawSecureSocket> connect( |
| 464 host, | 485 host, |
| 465 int requestedPort, | 486 int requestedPort, |
| 466 String certificateName, | 487 String certificateName, |
| 467 {bool is_server, | 488 {bool is_server, |
| 468 RawSocket socket, | 489 RawSocket socket, |
| 469 StreamSubscription subscription, | 490 StreamSubscription subscription, |
| 470 List<int> bufferedData, | 491 List<int> bufferedData, |
| 471 bool requestClientCertificate: false, | 492 bool requestClientCertificate: false, |
| 472 bool requireClientCertificate: false, | 493 bool requireClientCertificate: false, |
| 473 bool sendClientCertificate: false, | 494 bool sendClientCertificate: false, |
| 474 bool onBadCertificate(X509Certificate certificate)}) { | 495 bool onBadCertificate(X509Certificate certificate), |
| 496 List<String> supportedProtocols}) { | |
| 475 _verifyFields(host, requestedPort, certificateName, is_server, | 497 _verifyFields(host, requestedPort, certificateName, is_server, |
| 476 requestClientCertificate, requireClientCertificate, | 498 requestClientCertificate, requireClientCertificate, |
| 477 sendClientCertificate, onBadCertificate); | 499 sendClientCertificate, onBadCertificate); |
| 478 if (host is InternetAddress) host = host.host; | 500 if (host is InternetAddress) host = host.host; |
| 479 var address = socket.address; | 501 var address = socket.address; |
| 480 if (host != null) address = address._cloneWithNewHost(host); | 502 if (host != null) address = address._cloneWithNewHost(host); |
| 481 return new _RawSecureSocket(address, | 503 return new _RawSecureSocket(address, |
| 482 requestedPort, | 504 requestedPort, |
| 483 certificateName, | 505 certificateName, |
| 484 is_server, | 506 is_server, |
| 485 socket, | 507 socket, |
| 486 subscription, | 508 subscription, |
| 487 bufferedData, | 509 bufferedData, |
| 488 requestClientCertificate, | 510 requestClientCertificate, |
| 489 requireClientCertificate, | 511 requireClientCertificate, |
| 490 sendClientCertificate, | 512 sendClientCertificate, |
| 491 onBadCertificate) | 513 onBadCertificate, |
| 514 supportedProtocols) | |
| 492 ._handshakeComplete.future; | 515 ._handshakeComplete.future; |
| 493 } | 516 } |
| 494 | 517 |
| 495 _RawSecureSocket( | 518 _RawSecureSocket( |
| 496 this.address, | 519 this.address, |
| 497 int requestedPort, | 520 int requestedPort, |
| 498 this.certificateName, | 521 this.certificateName, |
| 499 this.is_server, | 522 this.is_server, |
| 500 RawSocket this._socket, | 523 RawSocket this._socket, |
| 501 this._socketSubscription, | 524 this._socketSubscription, |
| 502 this._bufferedData, | 525 this._bufferedData, |
| 503 this.requestClientCertificate, | 526 this.requestClientCertificate, |
| 504 this.requireClientCertificate, | 527 this.requireClientCertificate, |
| 505 this.sendClientCertificate, | 528 this.sendClientCertificate, |
| 506 this.onBadCertificate(X509Certificate certificate)) { | 529 this.onBadCertificate(X509Certificate certificate), |
| 530 List<String> supportedProtocols) { | |
| 507 _controller = new StreamController<RawSocketEvent>( | 531 _controller = new StreamController<RawSocketEvent>( |
| 508 sync: true, | 532 sync: true, |
| 509 onListen: _onSubscriptionStateChange, | 533 onListen: _onSubscriptionStateChange, |
| 510 onPause: _onPauseStateChange, | 534 onPause: _onPauseStateChange, |
| 511 onResume: _onPauseStateChange, | 535 onResume: _onPauseStateChange, |
| 512 onCancel: _onSubscriptionStateChange); | 536 onCancel: _onSubscriptionStateChange); |
| 513 _stream = _controller.stream; | 537 _stream = _controller.stream; |
| 514 // Throw an ArgumentError if any field is invalid. After this, all | 538 // Throw an ArgumentError if any field is invalid. After this, all |
| 515 // errors will be reported through the future or the stream. | 539 // errors will be reported through the future or the stream. |
| 516 _secureFilter.init(); | 540 _secureFilter.init(); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 541 } | 565 } |
| 542 try { | 566 try { |
| 543 _secureFilter.connect(address.host, | 567 _secureFilter.connect(address.host, |
| 544 (address as dynamic)._in_addr, | 568 (address as dynamic)._in_addr, |
| 545 port, | 569 port, |
| 546 is_server, | 570 is_server, |
| 547 certificateName, | 571 certificateName, |
| 548 requestClientCertificate || | 572 requestClientCertificate || |
| 549 requireClientCertificate, | 573 requireClientCertificate, |
| 550 requireClientCertificate, | 574 requireClientCertificate, |
| 551 sendClientCertificate); | 575 sendClientCertificate, |
| 576 _protocolsToLengthEncoding(supportedProtocols)); | |
| 552 _secureHandshake(); | 577 _secureHandshake(); |
| 553 } catch (e, s) { | 578 } catch (e, s) { |
| 554 _reportError(e, s); | 579 _reportError(e, s); |
| 555 } | 580 } |
| 556 } | 581 } |
| 557 | 582 |
| 583 /// Encodes a set of supported protocols for ALPN/NPN usage. | |
| 584 /// | |
| 585 /// The `protocols` list is expected to contain protocols in descending order | |
| 586 /// of preference. | |
| 587 /// | |
| 588 /// See RFC 7301 (https://tools.ietf.org/html/rfc7301) for the encoding of | |
| 589 /// `List<String> protocols`: | |
| 590 /// opaque ProtocolName<1..2^8-1>; | |
| 591 /// | |
| 592 /// struct { | |
| 593 /// ProtocolName protocol_name_list<2..2^16-1> | |
| 594 /// } ProtocolNameList; | |
| 595 /// | |
| 596 /// The encoding of the opaque `ProtocolName<lower..upper>` vector is | |
| 597 /// described in RFC 2246: 4.3 Vectors. | |
| 598 /// | |
| 599 /// Note: Even though this encoding scheme would allow a total | |
| 600 /// `ProtocolNameList` length of 65535, this limit cannot be reached. Testing | |
| 601 /// showed that more than ~ 65480 bytes will fail to negogiate a protocol. | |
| 602 /// We will be conservative and support only messages up to (1<<15) -1 bytes. | |
| 603 /// | |
| 604 /// Our NSS implementation will support ALPN and NPN transparently. The | |
| 605 /// default protocol will be the first in the encoded Uint8List. | |
| 606 /// | |
| 607 /// NOTE: The NSS library will treat the first protocol as the fallback | |
| 608 /// protocol. The remaining ones are sorted in (decreasing) priority order. | |
| 609 /// We therefore put the protocol least desired tothe front, to make it the | |
|
Søren Gjesse
2014/11/10 11:37:59
tothe -> to the
kustermann
2014/11/10 12:30:21
Done.
| |
| 610 /// default. | |
| 611 Uint8List _protocolsToLengthEncoding(List<String> protocols) { | |
| 612 if (protocols == null || protocols.length == 0) { | |
| 613 return new Uint8List(0); | |
| 614 } | |
| 615 int protocolsLength = protocols.length; | |
| 616 | |
| 617 // Calculate the number of bytes we will need if it is ASCII. | |
| 618 int expectedLength = protocolsLength; | |
| 619 for (int i = 0; i < protocolsLength; i++) { | |
| 620 int length = protocols[i].length; | |
| 621 if (length > 0 && length <= 255) { | |
| 622 expectedLength += length; | |
| 623 } else { | |
| 624 throw new ArgumentError( | |
| 625 'Length of protocol must be between 1 and 255 (was: $length).'); | |
| 626 } | |
| 627 } | |
| 628 | |
| 629 if (expectedLength >= (1 << 15)) { | |
| 630 throw new ArgumentError( | |
| 631 'The maximum message length supported is 2^15-1.'); | |
| 632 } | |
| 633 | |
| 634 // Try encoding the `List<String> protocols` array using fast ASCII path. | |
| 635 var bytes = new Uint8List(expectedLength); | |
| 636 int bytesOffset = 0; | |
| 637 for (int i = 0; i < protocolsLength; i++) { | |
| 638 // The last protocol will be encoded as the first/default one in the list. | |
| 639 // (i.e. rotate `protocols` by 1 to the right). | |
| 640 int index = i; | |
| 641 if (index == 0) index = protocols.length; | |
| 642 String proto = protocols[index - 1]; | |
| 643 | |
| 644 // Add length byte. | |
| 645 bytes[bytesOffset++] = proto.length; | |
| 646 int bits = 0; | |
| 647 | |
| 648 // Add protocol bytes. | |
| 649 for (int j = 0; j < proto.length; j++) { | |
| 650 var char = proto.codeUnitAt(j); | |
| 651 bits |= char; | |
| 652 bytes[bytesOffset++] = char & 0xff; | |
| 653 } | |
| 654 | |
| 655 // Go slow case if we have encountered anything non-ascii. | |
| 656 if (bits > 0x7f) { | |
| 657 return _protocolsToLengthEncodingNonAsciiBailout(protocols); | |
| 658 } | |
| 659 } | |
| 660 return bytes; | |
| 661 } | |
| 662 | |
| 663 Uint8List _protocolsToLengthEncodingNonAsciiBailout(List<String> protocols) { | |
| 664 void addProtocol(List<int> outBytes, String protocol) { | |
| 665 var protocolBytes = UTF8.encode(protocol); | |
| 666 var len = protocolBytes.length; | |
| 667 | |
| 668 if (len > 255) { | |
| 669 throw new ArgumentError( | |
| 670 'Length of protocol must be between 1 and 255 (was: $len)'); | |
| 671 } | |
| 672 // Add length byte. | |
| 673 outBytes.add(len); | |
| 674 | |
| 675 // Add protocol bytes. | |
| 676 outBytes.addAll(protocolBytes); | |
| 677 } | |
| 678 | |
| 679 List<int> bytes = []; | |
| 680 addProtocol(bytes, protocols.last); | |
| 681 for (var i = 0; i < protocols.length -1; i++) { | |
| 682 addProtocol(bytes, protocols[i]); | |
| 683 } | |
| 684 | |
| 685 if (bytes.length >= (1 << 15)) { | |
| 686 throw new ArgumentError( | |
| 687 'The maximum message length supported is 2^15-1.'); | |
| 688 } | |
| 689 | |
| 690 return new Uint8List.fromList(bytes); | |
| 691 } | |
| 692 | |
| 693 void _addProtocolBytes(List<int> outBytes, String protocol) { | |
| 694 var protocolBytes = UTF8.encode(protocol); | |
| 695 var len = protocolBytes.length; | |
| 696 | |
| 697 if (len > 255) { | |
| 698 throw new ArgumentError( | |
| 699 'Cannot support protocols with more than 255 characters'); | |
| 700 } | |
| 701 outBytes.add(len); | |
| 702 outBytes.addAll(protocolBytes); | |
| 703 } | |
| 704 | |
| 558 StreamSubscription listen(void onData(RawSocketEvent data), | 705 StreamSubscription listen(void onData(RawSocketEvent data), |
| 559 {Function onError, | 706 {Function onError, |
| 560 void onDone(), | 707 void onDone(), |
| 561 bool cancelOnError}) { | 708 bool cancelOnError}) { |
| 562 _sendWriteEvent(); | 709 _sendWriteEvent(); |
| 563 return _stream.listen(onData, | 710 return _stream.listen(onData, |
| 564 onError: onError, | 711 onError: onError, |
| 565 onDone: onDone, | 712 onDone: onDone, |
| 566 cancelOnError: cancelOnError); | 713 cancelOnError: cancelOnError); |
| 567 } | 714 } |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 725 _secureFilter.buffers[WRITE_PLAINTEXT].write(data, offset, bytes); | 872 _secureFilter.buffers[WRITE_PLAINTEXT].write(data, offset, bytes); |
| 726 if (written > 0) { | 873 if (written > 0) { |
| 727 _filterStatus.writeEmpty = false; | 874 _filterStatus.writeEmpty = false; |
| 728 } | 875 } |
| 729 _scheduleFilter(); | 876 _scheduleFilter(); |
| 730 return written; | 877 return written; |
| 731 } | 878 } |
| 732 | 879 |
| 733 X509Certificate get peerCertificate => _secureFilter.peerCertificate; | 880 X509Certificate get peerCertificate => _secureFilter.peerCertificate; |
| 734 | 881 |
| 882 String get selectedProtocol => _selectedProtocol; | |
| 883 | |
| 735 bool _onBadCertificateWrapper(X509Certificate certificate) { | 884 bool _onBadCertificateWrapper(X509Certificate certificate) { |
| 736 if (onBadCertificate == null) return false; | 885 if (onBadCertificate == null) return false; |
| 737 var result = onBadCertificate(certificate); | 886 var result = onBadCertificate(certificate); |
| 738 if (result is bool) return result; | 887 if (result is bool) return result; |
| 739 throw new ArgumentError( | 888 throw new ArgumentError( |
| 740 "onBadCertificate callback returned non-boolean $result"); | 889 "onBadCertificate callback returned non-boolean $result"); |
| 741 } | 890 } |
| 742 | 891 |
| 743 bool setOption(SocketOption option, bool enabled) { | 892 bool setOption(SocketOption option, bool enabled) { |
| 744 if (_socket == null) return false; | 893 if (_socket == null) return false; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 838 requireClientCertificate); | 987 requireClientCertificate); |
| 839 _status = HANDSHAKE; | 988 _status = HANDSHAKE; |
| 840 _filterStatus.writeEmpty = false; | 989 _filterStatus.writeEmpty = false; |
| 841 _scheduleFilter(); | 990 _scheduleFilter(); |
| 842 } | 991 } |
| 843 | 992 |
| 844 void _secureHandshakeCompleteHandler() { | 993 void _secureHandshakeCompleteHandler() { |
| 845 _status = CONNECTED; | 994 _status = CONNECTED; |
| 846 if (_connectPending) { | 995 if (_connectPending) { |
| 847 _connectPending = false; | 996 _connectPending = false; |
| 848 // We don't want user code to run synchronously in this callback. | 997 try { |
| 849 Timer.run(() => _handshakeComplete.complete(this)); | 998 _selectedProtocol = _secureFilter.selectedProtocol(); |
| 999 // We don't want user code to run synchronously in this callback. | |
| 1000 Timer.run(() => _handshakeComplete.complete(this)); | |
| 1001 } catch (error, stack) { | |
| 1002 _handshakeComplete.completeError(error, stack); | |
| 1003 } | |
| 850 } | 1004 } |
| 851 } | 1005 } |
| 852 | 1006 |
| 853 void _onPauseStateChange() { | 1007 void _onPauseStateChange() { |
| 854 if (_controller.isPaused) { | 1008 if (_controller.isPaused) { |
| 855 _pauseCount++; | 1009 _pauseCount++; |
| 856 } else { | 1010 } else { |
| 857 _pauseCount--; | 1011 _pauseCount--; |
| 858 if (_pauseCount == 0) { | 1012 if (_pauseCount == 0) { |
| 859 _scheduleReadEvent(); | 1013 _scheduleReadEvent(); |
| (...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1199 abstract class _SecureFilter { | 1353 abstract class _SecureFilter { |
| 1200 external factory _SecureFilter(); | 1354 external factory _SecureFilter(); |
| 1201 | 1355 |
| 1202 void connect(String hostName, | 1356 void connect(String hostName, |
| 1203 Uint8List addr, | 1357 Uint8List addr, |
| 1204 int port, | 1358 int port, |
| 1205 bool is_server, | 1359 bool is_server, |
| 1206 String certificateName, | 1360 String certificateName, |
| 1207 bool requestClientCertificate, | 1361 bool requestClientCertificate, |
| 1208 bool requireClientCertificate, | 1362 bool requireClientCertificate, |
| 1209 bool sendClientCertificate); | 1363 bool sendClientCertificate, |
| 1364 Uint8List protocols); | |
| 1210 void destroy(); | 1365 void destroy(); |
| 1211 void handshake(); | 1366 void handshake(); |
| 1212 void rehandshake(); | 1367 void rehandshake(); |
| 1213 void renegotiate(bool useSessionCache, | 1368 void renegotiate(bool useSessionCache, |
| 1214 bool requestClientCertificate, | 1369 bool requestClientCertificate, |
| 1215 bool requireClientCertificate); | 1370 bool requireClientCertificate); |
| 1216 void init(); | 1371 void init(); |
| 1217 X509Certificate get peerCertificate; | 1372 X509Certificate get peerCertificate; |
| 1218 int processBuffer(int bufferIndex); | 1373 int processBuffer(int bufferIndex); |
| 1219 void registerBadCertificateCallback(Function callback); | 1374 void registerBadCertificateCallback(Function callback); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1267 /** | 1422 /** |
| 1268 * An exception that happens in the handshake phase of establishing | 1423 * An exception that happens in the handshake phase of establishing |
| 1269 * a secure network connection, when looking up or verifying a | 1424 * a secure network connection, when looking up or verifying a |
| 1270 * certificate. | 1425 * certificate. |
| 1271 */ | 1426 */ |
| 1272 class CertificateException extends TlsException { | 1427 class CertificateException extends TlsException { |
| 1273 const CertificateException([String message = "", | 1428 const CertificateException([String message = "", |
| 1274 OSError osError = null]) | 1429 OSError osError = null]) |
| 1275 : super._("CertificateException", message, osError); | 1430 : super._("CertificateException", message, osError); |
| 1276 } | 1431 } |
| OLD | NEW |