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

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: Fix bad upload to review tool. 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 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 /** 143 /**
144 * Get the peer certificate for a connected SecureSocket. If this 144 * Get the peer certificate for a connected SecureSocket. If this
145 * SecureSocket is the server end of a secure socket connection, 145 * SecureSocket is the server end of a secure socket connection,
146 * [peerCertificate] will return the client certificate, or null, if no 146 * [peerCertificate] will return the client certificate, or null, if no
147 * client certificate was received. If it is the client end, 147 * client certificate was received. If it is the client end,
148 * [peerCertificate] will return the server's certificate. 148 * [peerCertificate] will return the server's certificate.
149 */ 149 */
150 X509Certificate get peerCertificate; 150 X509Certificate get peerCertificate;
151 151
152 /** 152 /**
153 * Initializes the NSS library. If [initialize] is not called, the library 153 * Initializes the NSS library. If [initialize] is not called, the library
154 * is automatically initialized as if [initialize] were called with no 154 * is automatically initialized as if [initialize] were called with no
155 * arguments. 155 * arguments. If [initialize] is called more than once, or called after
156 * automatic initialization has happened (when a secure connection is made),
157 * then a TlsException is thrown.
156 * 158 *
157 * The optional argument [database] is the path to a certificate database 159 * The optional argument [database] is the path to a certificate database
158 * directory containing root certificates for verifying certificate paths on 160 * directory containing root certificates for verifying certificate paths on
159 * client connections, and server certificates to provide on server 161 * client connections, and server certificates to provide on server
160 * connections. The argument [password] should be used when creating 162 * connections. The argument [password] should be used when creating
161 * secure server sockets, to allow the private key of the server 163 * secure server sockets, to allow the private key of the server
162 * certificate to be fetched. If [useBuiltinRoots] is true (the default), 164 * certificate to be fetched. If [useBuiltinRoots] is true (the default),
163 * then a built-in set of root certificates for trusted certificate 165 * then a built-in set of root certificates for trusted certificate
164 * authorities is merged with the certificates in the database. 166 * authorities is merged with the certificates in the database.
165 * The list of built-in root certificates, and documentation about this 167 * The list of built-in root certificates, and documentation about this
166 * default database, is available at 168 * default database, is available at
167 * http://www.mozilla.org/projects/security/certs/included/ . 169 * http://www.mozilla.org/projects/security/certs/included/ .
168 * 170 *
169 * If the [database] argument is omitted, then only the 171 * If the [database] argument is omitted, then only the
170 * builtin root certificates are used. If [useBuiltinRoots] is also false, 172 * builtin root certificates are used. If [useBuiltinRoots] is also false,
171 * then no certificates are available. 173 * then no certificates are available.
172 * 174 *
173 * Examples: 175 * Examples:
174 * 1) Use only the builtin root certificates: 176 * 1) Use only the builtin root certificates:
175 * SecureSocket.initialize(); or 177 * SecureSocket.initialize(); or
176 * 178 *
177 * 2) Use a specified database directory and the builtin roots: 179 * 2) Use a specified database directory and the builtin roots:
178 * SecureSocket.initialize(database: 'path/to/my/database', 180 * SecureSocket.initialize(database: 'path/to/my/database',
179 * password: 'my_password'); 181 * password: 'my_password');
180 * 182 *
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 String certificateName, 432 String certificateName,
431 {bool is_server, 433 {bool is_server,
432 RawSocket socket, 434 RawSocket socket,
433 StreamSubscription subscription, 435 StreamSubscription subscription,
434 List<int> bufferedData, 436 List<int> bufferedData,
435 bool requestClientCertificate: false, 437 bool requestClientCertificate: false,
436 bool requireClientCertificate: false, 438 bool requireClientCertificate: false,
437 bool sendClientCertificate: false, 439 bool sendClientCertificate: false,
438 bool onBadCertificate(X509Certificate certificate)}) { 440 bool onBadCertificate(X509Certificate certificate)}) {
439 var future; 441 var future;
442 _verifyFields(host, requestedPort, certificateName, is_server,
443 requestClientCertificate, requireClientCertificate,
444 sendClientCertificate, onBadCertificate);
440 if (host is String) { 445 if (host is String) {
441 if (socket != null) { 446 if (socket != null) {
442 future = new Future.value( 447 future = new Future.value(
443 (socket.address as dynamic)._cloneWithNewHost(host)); 448 (socket.address as dynamic)._cloneWithNewHost(host));
444 } else { 449 } else {
445 future = InternetAddress.lookup(host).then((addrs) => addrs.first); 450 future = InternetAddress.lookup(host).then((addrs) => addrs.first);
446 } 451 }
447 } else { 452 } else {
448 future = new Future.value(host); 453 future = new Future.value(host);
449 } 454 }
(...skipping 27 matching lines...) Expand all
477 bool this.onBadCertificate(X509Certificate certificate)) { 482 bool this.onBadCertificate(X509Certificate certificate)) {
478 _controller = new StreamController<RawSocketEvent>( 483 _controller = new StreamController<RawSocketEvent>(
479 sync: true, 484 sync: true,
480 onListen: _onSubscriptionStateChange, 485 onListen: _onSubscriptionStateChange,
481 onPause: _onPauseStateChange, 486 onPause: _onPauseStateChange,
482 onResume: _onPauseStateChange, 487 onResume: _onPauseStateChange,
483 onCancel: _onSubscriptionStateChange); 488 onCancel: _onSubscriptionStateChange);
484 _stream = _controller.stream; 489 _stream = _controller.stream;
485 // Throw an ArgumentError if any field is invalid. After this, all 490 // Throw an ArgumentError if any field is invalid. After this, all
486 // errors will be reported through the future or the stream. 491 // errors will be reported through the future or the stream.
487 _verifyFields();
488 _secureFilter.init(); 492 _secureFilter.init();
489 _filterPointer = _secureFilter._pointer(); 493 _filterPointer = _secureFilter._pointer();
490 _secureFilter.registerHandshakeCompleteCallback( 494 _secureFilter.registerHandshakeCompleteCallback(
491 _secureHandshakeCompleteHandler); 495 _secureHandshakeCompleteHandler);
492 if (onBadCertificate != null) { 496 if (onBadCertificate != null) {
493 _secureFilter.registerBadCertificateCallback(onBadCertificate); 497 _secureFilter.registerBadCertificateCallback(onBadCertificate);
494 } 498 }
495 var futureSocket; 499 var futureSocket;
496 if (socket == null) { 500 if (socket == null) {
497 futureSocket = RawSocket.connect(address, requestedPort); 501 futureSocket = RawSocket.connect(address, requestedPort);
498 } else { 502 } else {
499 futureSocket = new Future.value(socket); 503 futureSocket = new Future.value(socket);
500 } 504 }
501 futureSocket.then((rawSocket) { 505 futureSocket.then((rawSocket) {
506 _connectPending = true;
502 _socket = rawSocket; 507 _socket = rawSocket;
503 _socket.readEventsEnabled = true; 508 _socket.readEventsEnabled = true;
504 _socket.writeEventsEnabled = false; 509 _socket.writeEventsEnabled = false;
505 if (_socketSubscription == null) { 510 if (_socketSubscription == null) {
506 // If a current subscription is provided use this otherwise 511 // If a current subscription is provided use this otherwise
507 // create a new one. 512 // create a new one.
508 _socketSubscription = _socket.listen(_eventDispatcher, 513 _socketSubscription = _socket.listen(_eventDispatcher,
509 onError: _errorHandler, 514 onError: _reportError,
510 onDone: _doneHandler); 515 onDone: _doneHandler);
511 } else { 516 } else {
512 _socketSubscription.onData(_eventDispatcher); 517 _socketSubscription.onData(_eventDispatcher);
513 _socketSubscription.onError(_errorHandler); 518 _socketSubscription.onError(_reportError);
514 _socketSubscription.onDone(_doneHandler); 519 _socketSubscription.onDone(_doneHandler);
515 } 520 }
516 _connectPending = true;
517 _secureFilter.connect(address.host, 521 _secureFilter.connect(address.host,
518 (address as dynamic)._sockaddr_storage, 522 (address as dynamic)._sockaddr_storage,
519 port, 523 port,
520 is_server, 524 is_server,
521 certificateName, 525 certificateName,
522 requestClientCertificate || 526 requestClientCertificate ||
523 requireClientCertificate, 527 requireClientCertificate,
524 requireClientCertificate, 528 requireClientCertificate,
525 sendClientCertificate); 529 sendClientCertificate);
526 _secureHandshake(); 530 _secureHandshake();
527 }) 531 })
528 .catchError((error) { 532 .catchError(_reportError);
529 _handshakeComplete.completeError(error);
530 _close();
531 });
532 } 533 }
533 534
534 StreamSubscription listen(void onData(RawSocketEvent data), 535 StreamSubscription listen(void onData(RawSocketEvent data),
535 {void onError(error), 536 {void onError(error),
536 void onDone(), 537 void onDone(),
537 bool cancelOnError}) { 538 bool cancelOnError}) {
538 _sendWriteEvent(); 539 _sendWriteEvent();
539 return _stream.listen(onData, 540 return _stream.listen(onData,
540 onError: onError, 541 onError: onError,
541 onDone: onDone, 542 onDone: onDone,
542 cancelOnError: cancelOnError); 543 cancelOnError: cancelOnError);
543 } 544 }
544 545
545 void _verifyFields() { 546 static void _verifyFields(host,
546 assert(is_server is bool); 547 int requestedPort,
547 assert(_socket == null || _socket is RawSocket); 548 String certificateName,
548 if (address is! InternetAddress) { 549 bool is_server,
549 throw new ArgumentError( 550 bool requestClientCertificate,
550 "RawSecureSocket constructor: host is not an InternetAddress"); 551 bool requireClientCertificate,
552 bool sendClientCertificate,
553 Function onBadCertificate) {
554 if (host is! String && host is! InternetAddress) {
555 throw new ArgumentError("host is not a String or an InternetAddress");
556 }
557 if (requestedPort is! int) {
558 throw new ArgumentError("requestedPort is not an int");
559 }
560 if (requestedPort < 0 || requestedPort > 65535) {
561 throw new ArgumentError("requestedPort is not in the range 0..65535");
551 } 562 }
552 if (certificateName != null && certificateName is! String) { 563 if (certificateName != null && certificateName is! String) {
553 throw new ArgumentError("certificateName is not null or a String"); 564 throw new ArgumentError("certificateName is not null or a String");
554 } 565 }
555 if (certificateName == null && is_server) { 566 if (certificateName == null && is_server) {
556 throw new ArgumentError("certificateName is null on a server"); 567 throw new ArgumentError("certificateName is null on a server");
557 } 568 }
558 if (requestClientCertificate is! bool) { 569 if (requestClientCertificate is! bool) {
559 throw new ArgumentError("requestClientCertificate is not a bool"); 570 throw new ArgumentError("requestClientCertificate is not a bool");
560 } 571 }
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
686 } 697 }
687 698
688 X509Certificate get peerCertificate => _secureFilter.peerCertificate; 699 X509Certificate get peerCertificate => _secureFilter.peerCertificate;
689 700
690 bool setOption(SocketOption option, bool enabled) { 701 bool setOption(SocketOption option, bool enabled) {
691 if (_socket == null) return false; 702 if (_socket == null) return false;
692 return _socket.setOption(option, enabled); 703 return _socket.setOption(option, enabled);
693 } 704 }
694 705
695 void _eventDispatcher(RawSocketEvent event) { 706 void _eventDispatcher(RawSocketEvent event) {
696 if (event == RawSocketEvent.READ) { 707 try {
697 _readHandler(); 708 if (event == RawSocketEvent.READ) {
698 } else if (event == RawSocketEvent.WRITE) { 709 _readHandler();
699 _writeHandler(); 710 } else if (event == RawSocketEvent.WRITE) {
700 } else if (event == RawSocketEvent.READ_CLOSED) { 711 _writeHandler();
701 _closeHandler(); 712 } else if (event == RawSocketEvent.READ_CLOSED) {
713 _closeHandler();
714 }
715 } catch (e) {
716 _reportError(e);
702 } 717 }
703 } 718 }
704 719
705 void _readHandler() { 720 void _readHandler() {
706 _readSocket(); 721 _readSocket();
707 _scheduleFilter(); 722 _scheduleFilter();
708 } 723 }
709 724
710 void _writeHandler() { 725 void _writeHandler() {
711 _writeSocket(); 726 _writeSocket();
712 _scheduleFilter(); 727 _scheduleFilter();
713 } 728 }
714 729
715 void _doneHandler() { 730 void _doneHandler() {
716 if (_filterStatus.readEmpty) { 731 if (_filterStatus.readEmpty) {
717 _close(); 732 _close();
718 } 733 }
719 } 734 }
720 735
721 void _errorHandler(e) { 736 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) { 737 if (_connectPending) {
738 // _connectPending is true after the underlying connection has been
739 // made, but before the handshake has completed.
740 if (e is! TlsException) {
741 e = new HandshakeException("$e", null);
742 }
735 _handshakeComplete.completeError(e); 743 _handshakeComplete.completeError(e);
736 } else { 744 } else {
737 _controller.addError(e); 745 _controller.addError(e);
738 } 746 }
739 _close(); 747 _close();
740 } 748 }
741 749
742 void _closeHandler() { 750 void _closeHandler() {
743 if (_status == CONNECTED) { 751 if (_status == CONNECTED) {
744 if (_closedRead) return; 752 if (_closedRead) return;
745 _socketClosedRead = true; 753 _socketClosedRead = true;
746 if (_filterStatus.readEmpty) { 754 if (_filterStatus.readEmpty) {
747 _closedRead = true; 755 _closedRead = true;
748 _controller.add(RawSocketEvent.READ_CLOSED); 756 _controller.add(RawSocketEvent.READ_CLOSED);
749 if (_socketClosedWrite) { 757 if (_socketClosedWrite) {
750 _close(); 758 _close();
751 } 759 }
752 } else { 760 } else {
753 _scheduleFilter(); 761 _scheduleFilter();
754 } 762 }
755 } else if (_status == HANDSHAKE) { 763 } else if (_status == HANDSHAKE) {
756 _socketClosedRead = true; 764 _socketClosedRead = true;
757 if (_filterStatus.readEmpty) { 765 if (_filterStatus.readEmpty) {
758 _reportError( 766 _reportError(
759 new SocketException('Connection terminated during handshake'), 767 new HandshakeException('Connection terminated during handshake'));
760 'RawSecureSocket error');
761 } else { 768 } else {
762 _secureHandshake(); 769 _secureHandshake();
763 } 770 }
764 } 771 }
765 } 772 }
766 773
767 void _secureHandshake() { 774 void _secureHandshake() {
768 try { 775 try {
769 _secureFilter.handshake(); 776 _secureFilter.handshake();
770 _filterStatus.writeEmpty = false; 777 _filterStatus.writeEmpty = false;
771 _readSocket(); 778 _readSocket();
772 _writeSocket(); 779 _writeSocket();
773 _scheduleFilter(); 780 _scheduleFilter();
774 } catch (e) { 781 } catch (e) {
775 _reportError(e, "RawSecureSocket error"); 782 _reportError(e);
776 } 783 }
777 } 784 }
778 785
779 void _secureHandshakeCompleteHandler() { 786 void _secureHandshakeCompleteHandler() {
780 _status = CONNECTED; 787 _status = CONNECTED;
781 if (_connectPending) { 788 if (_connectPending) {
782 _connectPending = false; 789 _connectPending = false;
783 // We don't want user code to run synchronously in this callback. 790 // We don't want user code to run synchronously in this callback.
784 Timer.run(() => _handshakeComplete.complete(this)); 791 Timer.run(() => _handshakeComplete.complete(this));
785 } 792 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
831 } 838 }
832 if (_filterStatus.writeEmpty && _closedWrite && !_socketClosedWrite) { 839 if (_filterStatus.writeEmpty && _closedWrite && !_socketClosedWrite) {
833 // Checks for and handles all cases of partially closed sockets. 840 // Checks for and handles all cases of partially closed sockets.
834 shutdown(SocketDirection.SEND); 841 shutdown(SocketDirection.SEND);
835 if (_status == CLOSED) return; 842 if (_status == CLOSED) return;
836 } 843 }
837 if (_filterStatus.readEmpty && _socketClosedRead && !_closedRead) { 844 if (_filterStatus.readEmpty && _socketClosedRead && !_closedRead) {
838 if (_status == HANDSHAKE) { 845 if (_status == HANDSHAKE) {
839 _secureFilter.handshake(); 846 _secureFilter.handshake();
840 if (_status == HANDSHAKE) { 847 if (_status == HANDSHAKE) {
841 _reportError( 848 throw new HandshakeException(
842 new SocketException('Connection terminated during handshake'), 849 'Connection terminated during handshake');
843 'RawSecureSocket error');
844 } 850 }
845 } 851 }
846 _closeHandler(); 852 _closeHandler();
847 } 853 }
848 if (_status == CLOSED) return; 854 if (_status == CLOSED) return;
849 if (_filterStatus.progress) { 855 if (_filterStatus.progress) {
850 _filterPending = true; 856 _filterPending = true;
851 if (_filterStatus.writePlaintextNoLongerFull) _sendWriteEvent(); 857 if (_filterStatus.writePlaintextNoLongerFull) _sendWriteEvent();
852 if (_filterStatus.readEncryptedNoLongerFull) _readSocket(); 858 if (_filterStatus.readEncryptedNoLongerFull) _readSocket();
853 if (_filterStatus.writeEncryptedNoLongerEmpty) _writeSocket(); 859 if (_filterStatus.writeEncryptedNoLongerEmpty) _writeSocket();
854 if (_filterStatus.readPlaintextNoLongerEmpty) _scheduleReadEvent(); 860 if (_filterStatus.readPlaintextNoLongerEmpty) _scheduleReadEvent();
855 if (_status == HANDSHAKE) _secureHandshake(); 861 if (_status == HANDSHAKE) _secureHandshake();
856 } 862 }
857 _tryFilter(); 863 _tryFilter();
858 }); 864 }).catchError(_reportError);
859 } 865 }
860 } 866 }
861 867
862 List<int> _readSocketOrBufferedData(int bytes) { 868 List<int> _readSocketOrBufferedData(int bytes) {
863 if (_bufferedData != null) { 869 if (_bufferedData != null) {
864 if (bytes > _bufferedData.length - _bufferedDataIndex) { 870 if (bytes > _bufferedData.length - _bufferedDataIndex) {
865 bytes = _bufferedData.length - _bufferedDataIndex; 871 bytes = _bufferedData.length - _bufferedDataIndex;
866 } 872 }
867 var result = _bufferedData.sublist(_bufferedDataIndex, 873 var result = _bufferedData.sublist(_bufferedDataIndex,
868 _bufferedDataIndex + bytes); 874 _bufferedDataIndex + bytes);
869 _bufferedDataIndex += bytes; 875 _bufferedDataIndex += bytes;
870 if (_bufferedData.length == _bufferedDataIndex) { 876 if (_bufferedData.length == _bufferedDataIndex) {
871 _bufferedData = null; 877 _bufferedData = null;
872 } 878 }
873 return result; 879 return result;
874 } else if (!_socketClosedRead) { 880 } else if (!_socketClosedRead) {
875 try { 881 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 { 882 } else {
882 return null; 883 return null;
883 } 884 }
884 } 885 }
885 886
886 void _readSocket() { 887 void _readSocket() {
887 if (_status == CLOSED) return; 888 if (_status == CLOSED) return;
888 var buffer = _secureFilter.buffers[READ_ENCRYPTED]; 889 var buffer = _secureFilter.buffers[READ_ENCRYPTED];
889 if (buffer.writeFromSource(_readSocketOrBufferedData) > 0) { 890 if (buffer.writeFromSource(_readSocketOrBufferedData) > 0) {
890 _filterStatus.readEmpty = false; 891 _filterStatus.readEmpty = false;
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
1154 void handshake(); 1155 void handshake();
1155 void init(); 1156 void init();
1156 X509Certificate get peerCertificate; 1157 X509Certificate get peerCertificate;
1157 int processBuffer(int bufferIndex); 1158 int processBuffer(int bufferIndex);
1158 void registerBadCertificateCallback(Function callback); 1159 void registerBadCertificateCallback(Function callback);
1159 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler); 1160 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler);
1160 int _pointer(); 1161 int _pointer();
1161 1162
1162 List<_ExternalBuffer> get buffers; 1163 List<_ExternalBuffer> get buffers;
1163 } 1164 }
1165
1166 /** A secure networking exception caused by a failure in the
1167 * TLS/SSL protocol.
1168 */
1169 class TlsException implements IOException {
1170 final String type;
1171 final String message;
1172 final OSError osError;
1173
1174 const TlsException([String message = "",
1175 OSError osError = null])
1176 : this._("TlsException", message, osError);
1177
1178 const TlsException._(String this.type,
1179 String this.message,
1180 OSError this.osError);
1181
1182 String toString() {
1183 StringBuffer sb = new StringBuffer();
1184 sb.write(type);
1185 if (!message.isEmpty) {
1186 sb.write(": $message");
1187 if (osError != null) {
1188 sb.write(" ($osError)");
1189 }
1190 } else if (osError != null) {
1191 sb.write(": $osError");
1192 }
1193 return sb.toString();
1194 }
1195 }
1196
1197
1198 /**
1199 * An exception that happens in the handshake phase of establishing
1200 * a secure network connection.
1201 */
1202 class HandshakeException extends TlsException {
1203 const HandshakeException([String message = "",
1204 OSError osError = null])
1205 : super._("HandshakeException", message, osError);
1206 }
1207
1208
1209 /**
1210 * An exception that happens in the handshake phase of establishing
1211 * a secure network connection, when looking up or verifying a
1212 * certificate.
1213 */
1214 class CertificateException extends TlsException {
1215 const CertificateException([String message = "",
1216 OSError osError = null])
1217 : super._("CertificateException", message, osError);
1218 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698