Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: sdk/lib/io/secure_socket.dart

Issue 17589007: dart:io | Change names for SecureSocket exceptions. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Move VerifyFields to throw ArgumentErrors Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 419 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 String certificateName, 430 String certificateName,
431 {bool is_server, 431 {bool is_server,
432 RawSocket socket, 432 RawSocket socket,
433 StreamSubscription subscription, 433 StreamSubscription subscription,
434 List<int> bufferedData, 434 List<int> bufferedData,
435 bool requestClientCertificate: false, 435 bool requestClientCertificate: false,
436 bool requireClientCertificate: false, 436 bool requireClientCertificate: false,
437 bool sendClientCertificate: false, 437 bool sendClientCertificate: false,
438 bool onBadCertificate(X509Certificate certificate)}) { 438 bool onBadCertificate(X509Certificate certificate)}) {
439 var future; 439 var future;
440 _verifyFields(host, requestedPort, certificateName, is_server,
441 requestClientCertificate, requireClientCertificate,
442 sendClientCertificate, onBadCertificate);
440 if (host is String) { 443 if (host is String) {
441 if (socket != null) { 444 if (socket != null) {
442 future = new Future.value( 445 future = new Future.value(
443 (socket.address as dynamic)._cloneWithNewHost(host)); 446 (socket.address as dynamic)._cloneWithNewHost(host));
444 } else { 447 } else {
445 future = InternetAddress.lookup(host).then((addrs) => addrs.first); 448 future = InternetAddress.lookup(host).then((addrs) => addrs.first);
446 } 449 }
447 } else { 450 } else {
448 future = new Future.value(host); 451 future = new Future.value(host);
449 } 452 }
(...skipping 27 matching lines...) Expand all
477 bool this.onBadCertificate(X509Certificate certificate)) { 480 bool this.onBadCertificate(X509Certificate certificate)) {
478 _controller = new StreamController<RawSocketEvent>( 481 _controller = new StreamController<RawSocketEvent>(
479 sync: true, 482 sync: true,
480 onListen: _onSubscriptionStateChange, 483 onListen: _onSubscriptionStateChange,
481 onPause: _onPauseStateChange, 484 onPause: _onPauseStateChange,
482 onResume: _onPauseStateChange, 485 onResume: _onPauseStateChange,
483 onCancel: _onSubscriptionStateChange); 486 onCancel: _onSubscriptionStateChange);
484 _stream = _controller.stream; 487 _stream = _controller.stream;
485 // Throw an ArgumentError if any field is invalid. After this, all 488 // Throw an ArgumentError if any field is invalid. After this, all
486 // errors will be reported through the future or the stream. 489 // errors will be reported through the future or the stream.
487 _verifyFields();
488 _secureFilter.init(); 490 _secureFilter.init();
489 _filterPointer = _secureFilter._pointer(); 491 _filterPointer = _secureFilter._pointer();
490 _secureFilter.registerHandshakeCompleteCallback( 492 _secureFilter.registerHandshakeCompleteCallback(
491 _secureHandshakeCompleteHandler); 493 _secureHandshakeCompleteHandler);
492 if (onBadCertificate != null) { 494 if (onBadCertificate != null) {
493 _secureFilter.registerBadCertificateCallback(onBadCertificate); 495 _secureFilter.registerBadCertificateCallback(onBadCertificate);
494 } 496 }
495 var futureSocket; 497 var futureSocket;
496 if (socket == null) { 498 if (socket == null) {
497 futureSocket = RawSocket.connect(address, requestedPort); 499 futureSocket = RawSocket.connect(address, requestedPort);
498 } else { 500 } else {
499 futureSocket = new Future.value(socket); 501 futureSocket = new Future.value(socket);
500 } 502 }
501 futureSocket.then((rawSocket) { 503 futureSocket.then((rawSocket) {
504 _connectPending = true;
502 _socket = rawSocket; 505 _socket = rawSocket;
503 _socket.readEventsEnabled = true; 506 _socket.readEventsEnabled = true;
504 _socket.writeEventsEnabled = false; 507 _socket.writeEventsEnabled = false;
505 if (_socketSubscription == null) { 508 if (_socketSubscription == null) {
506 // If a current subscription is provided use this otherwise 509 // If a current subscription is provided use this otherwise
507 // create a new one. 510 // create a new one.
508 _socketSubscription = _socket.listen(_eventDispatcher, 511 _socketSubscription = _socket.listen(_eventDispatcher,
509 onError: _errorHandler, 512 onError: _reportError,
510 onDone: _doneHandler); 513 onDone: _doneHandler);
511 } else { 514 } else {
512 _socketSubscription.onData(_eventDispatcher); 515 _socketSubscription.onData(_eventDispatcher);
513 _socketSubscription.onError(_errorHandler); 516 _socketSubscription.onError(_reportError);
514 _socketSubscription.onDone(_doneHandler); 517 _socketSubscription.onDone(_doneHandler);
515 } 518 }
516 _connectPending = true;
517 _secureFilter.connect(address.host, 519 _secureFilter.connect(address.host,
518 (address as dynamic)._sockaddr_storage, 520 (address as dynamic)._sockaddr_storage,
519 port, 521 port,
520 is_server, 522 is_server,
521 certificateName, 523 certificateName,
522 requestClientCertificate || 524 requestClientCertificate ||
523 requireClientCertificate, 525 requireClientCertificate,
524 requireClientCertificate, 526 requireClientCertificate,
525 sendClientCertificate); 527 sendClientCertificate);
526 _secureHandshake(); 528 _secureHandshake();
527 }) 529 })
528 .catchError((error) { 530 .catchError(_reportError);
529 _handshakeComplete.completeError(error);
530 _close();
531 });
532 } 531 }
533 532
534 StreamSubscription listen(void onData(RawSocketEvent data), 533 StreamSubscription listen(void onData(RawSocketEvent data),
535 {void onError(error), 534 {void onError(error),
536 void onDone(), 535 void onDone(),
537 bool cancelOnError}) { 536 bool cancelOnError}) {
538 _sendWriteEvent(); 537 _sendWriteEvent();
539 return _stream.listen(onData, 538 return _stream.listen(onData,
540 onError: onError, 539 onError: onError,
541 onDone: onDone, 540 onDone: onDone,
542 cancelOnError: cancelOnError); 541 cancelOnError: cancelOnError);
543 } 542 }
544 543
545 void _verifyFields() { 544 static void _verifyFields(host,
Søren Gjesse 2013/06/25 06:35:49 Indentation.
Bill Hesse 2013/06/25 12:41:14 Done.
546 assert(is_server is bool); 545 int requestedPort,
547 assert(_socket == null || _socket is RawSocket); 546 String certificateName,
548 if (address is! InternetAddress) { 547 bool is_server,
549 throw new ArgumentError( 548 bool requestClientCertificate,
550 "RawSecureSocket constructor: host is not an InternetAddress"); 549 bool requireClientCertificate,
550 bool sendClientCertificate,
551 Function onBadCertificate) {
552 if (host is! String && host is! InternetAddress) {
553 throw new ArgumentError("host is not a String or an InternetAddress");
554 }
555 if (requestedPort is! int) {
556 throw new ArgumentError("requestedPort is not an int");
557 }
558 if (requestedPort < 0 || requestedPort > 65535) {
559 throw new ArgumentError("requestedPort is not in the range 0..65535");
551 } 560 }
552 if (certificateName != null && certificateName is! String) { 561 if (certificateName != null && certificateName is! String) {
553 throw new ArgumentError("certificateName is not null or a String"); 562 throw new ArgumentError("certificateName is not null or a String");
554 } 563 }
555 if (certificateName == null && is_server) { 564 if (certificateName == null && is_server) {
556 throw new ArgumentError("certificateName is null on a server"); 565 throw new ArgumentError("certificateName is null on a server");
557 } 566 }
558 if (requestClientCertificate is! bool) { 567 if (requestClientCertificate is! bool) {
559 throw new ArgumentError("requestClientCertificate is not a bool"); 568 throw new ArgumentError("requestClientCertificate is not a bool");
560 } 569 }
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
686 } 695 }
687 696
688 X509Certificate get peerCertificate => _secureFilter.peerCertificate; 697 X509Certificate get peerCertificate => _secureFilter.peerCertificate;
689 698
690 bool setOption(SocketOption option, bool enabled) { 699 bool setOption(SocketOption option, bool enabled) {
691 if (_socket == null) return false; 700 if (_socket == null) return false;
692 return _socket.setOption(option, enabled); 701 return _socket.setOption(option, enabled);
693 } 702 }
694 703
695 void _eventDispatcher(RawSocketEvent event) { 704 void _eventDispatcher(RawSocketEvent event) {
696 if (event == RawSocketEvent.READ) { 705 try {
697 _readHandler(); 706 if (event == RawSocketEvent.READ) {
698 } else if (event == RawSocketEvent.WRITE) { 707 _readHandler();
699 _writeHandler(); 708 } else if (event == RawSocketEvent.WRITE) {
700 } else if (event == RawSocketEvent.READ_CLOSED) { 709 _writeHandler();
701 _closeHandler(); 710 } else if (event == RawSocketEvent.READ_CLOSED) {
711 _closeHandler();
712 }
713 } catch (e) {
714 _reportError(e);
702 } 715 }
703 } 716 }
704 717
705 void _readHandler() { 718 void _readHandler() {
706 _readSocket(); 719 _readSocket();
707 _scheduleFilter(); 720 _scheduleFilter();
708 } 721 }
709 722
710 void _writeHandler() { 723 void _writeHandler() {
711 _writeSocket(); 724 _writeSocket();
712 _scheduleFilter(); 725 _scheduleFilter();
713 } 726 }
714 727
715 void _doneHandler() { 728 void _doneHandler() {
716 if (_filterStatus.readEmpty) { 729 if (_filterStatus.readEmpty) {
717 _close(); 730 _close();
718 } 731 }
719 } 732 }
720 733
721 void _errorHandler(e) { 734 void _reportError(e) {
722 _reportError(e, 'Error on underlying RawSocket');
723 }
724
725 void _reportError(e, String message) {
726 // TODO(whesse): Call _reportError from all internal functions that throw.
727 if (e is SocketException) {
728 e = new SocketException('$message (${e.message})', e.osError);
729 } else if (e is OSError) {
730 e = new SocketException(message, e);
731 } else {
732 e = new SocketException('$message (${e.toString()})', null);
733 }
734 if (_connectPending) { 735 if (_connectPending) {
736 // _connectPending is true after the underlying connection has been
737 // made, but before the handshake has completed.
738 if (e is! TlsException) {
739 e = new HandshakeException("$e", null);
740 }
735 _handshakeComplete.completeError(e); 741 _handshakeComplete.completeError(e);
736 } else { 742 } else {
737 _controller.addError(e); 743 _controller.addError(e);
738 } 744 }
739 _close(); 745 _close();
740 } 746 }
741 747
742 void _closeHandler() { 748 void _closeHandler() {
743 if (_status == CONNECTED) { 749 if (_status == CONNECTED) {
744 if (_closedRead) return; 750 if (_closedRead) return;
745 _socketClosedRead = true; 751 _socketClosedRead = true;
746 if (_filterStatus.readEmpty) { 752 if (_filterStatus.readEmpty) {
747 _closedRead = true; 753 _closedRead = true;
748 _controller.add(RawSocketEvent.READ_CLOSED); 754 _controller.add(RawSocketEvent.READ_CLOSED);
749 if (_socketClosedWrite) { 755 if (_socketClosedWrite) {
750 _close(); 756 _close();
751 } 757 }
752 } else { 758 } else {
753 _scheduleFilter(); 759 _scheduleFilter();
754 } 760 }
755 } else if (_status == HANDSHAKE) { 761 } else if (_status == HANDSHAKE) {
756 _socketClosedRead = true; 762 _socketClosedRead = true;
757 if (_filterStatus.readEmpty) { 763 if (_filterStatus.readEmpty) {
758 _reportError( 764 _reportError(
759 new SocketException('Connection terminated during handshake'), 765 new HandshakeException('Connection terminated during handshake'));
760 'RawSecureSocket error');
761 } else { 766 } else {
762 _secureHandshake(); 767 _secureHandshake();
763 } 768 }
764 } 769 }
765 } 770 }
766 771
767 void _secureHandshake() { 772 void _secureHandshake() {
768 try { 773 try {
769 _secureFilter.handshake(); 774 _secureFilter.handshake();
770 _filterStatus.writeEmpty = false; 775 _filterStatus.writeEmpty = false;
771 _readSocket(); 776 _readSocket();
772 _writeSocket(); 777 _writeSocket();
773 _scheduleFilter(); 778 _scheduleFilter();
774 } catch (e) { 779 } catch (e) {
775 _reportError(e, "RawSecureSocket error"); 780 _reportError(e);
776 } 781 }
777 } 782 }
778 783
779 void _secureHandshakeCompleteHandler() { 784 void _secureHandshakeCompleteHandler() {
780 _status = CONNECTED; 785 _status = CONNECTED;
781 if (_connectPending) { 786 if (_connectPending) {
782 _connectPending = false; 787 _connectPending = false;
783 // We don't want user code to run synchronously in this callback. 788 // We don't want user code to run synchronously in this callback.
784 Timer.run(() => _handshakeComplete.complete(this)); 789 Timer.run(() => _handshakeComplete.complete(this));
785 } 790 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
831 } 836 }
832 if (_filterStatus.writeEmpty && _closedWrite && !_socketClosedWrite) { 837 if (_filterStatus.writeEmpty && _closedWrite && !_socketClosedWrite) {
833 // Checks for and handles all cases of partially closed sockets. 838 // Checks for and handles all cases of partially closed sockets.
834 shutdown(SocketDirection.SEND); 839 shutdown(SocketDirection.SEND);
835 if (_status == CLOSED) return; 840 if (_status == CLOSED) return;
836 } 841 }
837 if (_filterStatus.readEmpty && _socketClosedRead && !_closedRead) { 842 if (_filterStatus.readEmpty && _socketClosedRead && !_closedRead) {
838 if (_status == HANDSHAKE) { 843 if (_status == HANDSHAKE) {
839 _secureFilter.handshake(); 844 _secureFilter.handshake();
840 if (_status == HANDSHAKE) { 845 if (_status == HANDSHAKE) {
841 _reportError( 846 throw new HandshakeException(
842 new SocketException('Connection terminated during handshake'), 847 'Connection terminated during handshake');
843 'RawSecureSocket error');
844 } 848 }
845 } 849 }
846 _closeHandler(); 850 _closeHandler();
847 } 851 }
848 if (_status == CLOSED) return; 852 if (_status == CLOSED) return;
849 if (_filterStatus.progress) { 853 if (_filterStatus.progress) {
850 _filterPending = true; 854 _filterPending = true;
851 if (_filterStatus.writePlaintextNoLongerFull) _sendWriteEvent(); 855 if (_filterStatus.writePlaintextNoLongerFull) _sendWriteEvent();
852 if (_filterStatus.readEncryptedNoLongerFull) _readSocket(); 856 if (_filterStatus.readEncryptedNoLongerFull) _readSocket();
853 if (_filterStatus.writeEncryptedNoLongerEmpty) _writeSocket(); 857 if (_filterStatus.writeEncryptedNoLongerEmpty) _writeSocket();
854 if (_filterStatus.readPlaintextNoLongerEmpty) _scheduleReadEvent(); 858 if (_filterStatus.readPlaintextNoLongerEmpty) _scheduleReadEvent();
855 if (_status == HANDSHAKE) _secureHandshake(); 859 if (_status == HANDSHAKE) _secureHandshake();
856 } 860 }
857 _tryFilter(); 861 _tryFilter();
858 }); 862 }).catchError(_reportError);
859 } 863 }
860 } 864 }
861 865
862 List<int> _readSocketOrBufferedData(int bytes) { 866 List<int> _readSocketOrBufferedData(int bytes) {
863 if (_bufferedData != null) { 867 if (_bufferedData != null) {
864 if (bytes > _bufferedData.length - _bufferedDataIndex) { 868 if (bytes > _bufferedData.length - _bufferedDataIndex) {
865 bytes = _bufferedData.length - _bufferedDataIndex; 869 bytes = _bufferedData.length - _bufferedDataIndex;
866 } 870 }
867 var result = _bufferedData.sublist(_bufferedDataIndex, 871 var result = _bufferedData.sublist(_bufferedDataIndex,
868 _bufferedDataIndex + bytes); 872 _bufferedDataIndex + bytes);
869 _bufferedDataIndex += bytes; 873 _bufferedDataIndex += bytes;
870 if (_bufferedData.length == _bufferedDataIndex) { 874 if (_bufferedData.length == _bufferedDataIndex) {
871 _bufferedData = null; 875 _bufferedData = null;
872 } 876 }
873 return result; 877 return result;
874 } else if (!_socketClosedRead) { 878 } else if (!_socketClosedRead) {
875 try { 879 return _socket.read(bytes);
876 return _socket.read(bytes);
877 } catch (e) {
878 _reportError(e, "RawSecureSocket error reading encrypted socket");
879 return null;
880 }
881 } else { 880 } else {
882 return null; 881 return null;
883 } 882 }
884 } 883 }
885 884
886 void _readSocket() { 885 void _readSocket() {
887 if (_status == CLOSED) return; 886 if (_status == CLOSED) return;
888 var buffer = _secureFilter.buffers[READ_ENCRYPTED]; 887 var buffer = _secureFilter.buffers[READ_ENCRYPTED];
889 if (buffer.writeFromSource(_readSocketOrBufferedData) > 0) { 888 if (buffer.writeFromSource(_readSocketOrBufferedData) > 0) {
890 _filterStatus.readEmpty = false; 889 _filterStatus.readEmpty = false;
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
1154 void handshake(); 1153 void handshake();
1155 void init(); 1154 void init();
1156 X509Certificate get peerCertificate; 1155 X509Certificate get peerCertificate;
1157 int processBuffer(int bufferIndex); 1156 int processBuffer(int bufferIndex);
1158 void registerBadCertificateCallback(Function callback); 1157 void registerBadCertificateCallback(Function callback);
1159 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler); 1158 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler);
1160 int _pointer(); 1159 int _pointer();
1161 1160
1162 List<_ExternalBuffer> get buffers; 1161 List<_ExternalBuffer> get buffers;
1163 } 1162 }
1163
1164 /** A secure networking exception caused by a failure in the
1165 * TLS/SSL protocol.
1166 */
1167 class TlsException implements IOException {
1168 const TlsException([String message = "",
1169 OSError osError = null])
1170 : this._("TlsException", message, osError);
1171
1172 const TlsException._(String this.type,
1173 String this.message,
1174 OSError this.osError);
1175
1176 String toString() {
1177 StringBuffer sb = new StringBuffer();
1178 sb.write(type);
1179 if (!message.isEmpty) {
1180 sb.write(": $message");
1181 if (osError != null) {
1182 sb.write(" ($osError)");
1183 }
1184 } else if (osError != null) {
1185 sb.write(": $osError");
1186 }
1187 return sb.toString();
1188 }
1189 final String type;
Anders Johnsen 2013/06/25 05:55:03 Move to top.
Bill Hesse 2013/06/25 12:41:14 Done.
1190 final String message;
1191 final OSError osError;
1192 }
1193
1194
1195 /**
1196 * An exception that happens in the handshake phase of establishing
1197 * a secure network connection.
1198 */
Søren Gjesse 2013/06/25 06:35:49 As mentioned before maybe just drop HandshakeExcep
1199 class HandshakeException extends TlsException {
1200 const HandshakeException([String message = "",
1201 OSError osError = null])
1202 : super._("HandshakeException", message, osError);
1203 }
1204
1205
1206 /**
1207 * An exception that happens in the handshake phase of establishing
1208 * a secure network connection, when looking up or verifying a
1209 * certificate.
1210 */
Søren Gjesse 2013/06/25 06:35:49 Ca we add some more information to this exception
Bill Hesse 2013/06/25 12:41:14 Done.
1211 class CertificateException extends TlsException {
1212 const CertificateException([String message = "",
1213 OSError osError = null])
1214 : super._("CertificateException", message, osError);
1215 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698