Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 /** | 5 /** |
| 6 * SecureSocket provides a secure (SSL or TLS) client connection to a server. | 6 * SecureSocket provides a secure (SSL or TLS) client connection to a server. |
| 7 * The certificate provided by the server is checked | 7 * The certificate provided by the server is checked |
| 8 * using the certificate database provided in setCertificateDatabase. | 8 * using the certificate database provided in setCertificateDatabase. |
| 9 */ | 9 */ |
| 10 abstract class SecureSocket implements Socket { | 10 abstract class SecureSocket implements Socket { |
| 11 /** | 11 /** |
| 12 * Constructs a new secure client socket and connect it to the given | 12 * Constructs a new secure client socket and connect it to the given |
| 13 * host on the given port. The returned socket is not yet connected | 13 * host on the given port. The returned socket is not yet connected |
| 14 * but ready for registration of callbacks. | 14 * but ready for registration of callbacks. |
| 15 */ | 15 */ |
| 16 factory SecureSocket(String host, int port) => new _SecureSocket(host, port); | 16 factory SecureSocket(String host, int port) => new _SecureSocket(host, port); |
| 17 | 17 |
| 18 /** | 18 /** |
| 19 * Initializes the NSS library with the path to a certificate database | 19 * Initializes the NSS library with the path to a certificate database |
|
Mads Ager (google)
2012/12/03 09:15:09
We should revisit this comment more. We should pro
| |
| 20 * containing root certificates for verifying certificate paths on | 20 * containing root certificates for verifying certificate paths on |
| 21 * client connections, and server certificates to provide on server | 21 * client connections, and server certificates to provide on server |
| 22 * connections. The password argument should be used when creating | 22 * connections. The password argument should be used when creating |
| 23 * secure server sockets, to allow the private key of the server | 23 * secure server sockets, to allow the private key of the server |
| 24 * certificate to be fetched. | 24 * certificate to be fetched. If useBuiltinRoots is true (the default), |
| 25 * then a built-in set of root certificates for trusted certificate | |
| 26 * authorities is merged with the certificates in the database. | |
| 25 * | 27 * |
| 26 * The database should be an NSS certificate database directory | 28 * The database should be an NSS certificate database directory |
| 27 * containing a cert9.db file, not a cert8.db file. This version of | 29 * containing a cert9.db file, not a cert8.db file. This version of |
| 28 * the database can be created using the NSS certutil tool with "sql:" in | 30 * the database can be created using the NSS certutil tool with "sql:" in |
| 29 * front of the absolute path of the database directory, or setting the | 31 * front of the absolute path of the database directory, or setting the |
| 30 * environment variable NSS_DEFAULT_DB_TYPE to "sql". | 32 * environment variable NSS_DEFAULT_DB_TYPE to "sql". |
| 31 */ | 33 */ |
| 32 external static void setCertificateDatabase(String certificateDatabase, | 34 external static void initialize({String database, |
| 33 [String password]); | 35 String password, |
| 36 bool useBuiltinRoots: true}); | |
| 34 } | 37 } |
| 35 | 38 |
| 36 | 39 |
| 37 class _SecureSocket implements SecureSocket { | 40 class _SecureSocket implements SecureSocket { |
| 38 // Status states | 41 // Status states |
| 39 static final int NOT_CONNECTED = 200; | 42 static final int NOT_CONNECTED = 200; |
| 40 static final int HANDSHAKE = 201; | 43 static final int HANDSHAKE = 201; |
| 41 static final int CONNECTED = 202; | 44 static final int CONNECTED = 202; |
| 42 static final int CLOSED = 203; | 45 static final int CLOSED = 203; |
| 43 | 46 |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 189 scheduledDataEvent.cancel(); | 192 scheduledDataEvent.cancel(); |
| 190 } | 193 } |
| 191 _status = CLOSED; | 194 _status = CLOSED; |
| 192 } | 195 } |
| 193 } | 196 } |
| 194 | 197 |
| 195 void _closeWrite() => close(true); | 198 void _closeWrite() => close(true); |
| 196 | 199 |
| 197 List<int> read([int len]) { | 200 List<int> read([int len]) { |
| 198 if (_closedRead) { | 201 if (_closedRead) { |
| 199 throw new SocketException("Reading from a closed socket"); | 202 throw new SocketIOException("Reading from a closed socket"); |
| 200 } | 203 } |
| 201 if (_status != CONNECTED) { | 204 if (_status != CONNECTED) { |
| 202 return new List<int>(0); | 205 return new List<int>(0); |
| 203 } | 206 } |
| 204 var buffer = _secureFilter.buffers[READ_PLAINTEXT]; | 207 var buffer = _secureFilter.buffers[READ_PLAINTEXT]; |
| 205 _readEncryptedData(); | 208 _readEncryptedData(); |
| 206 int toRead = buffer.length; | 209 int toRead = buffer.length; |
| 207 if (len != null) { | 210 if (len != null) { |
| 208 if (len is! int || len < 0) { | 211 if (len is! int || len < 0) { |
| 209 throw new ArgumentError( | 212 throw new ArgumentError( |
| 210 "Invalid len parameter in SecureSocket.read (len: $len)"); | 213 "Invalid len parameter in SecureSocket.read (len: $len)"); |
| 211 } | 214 } |
| 212 if (len < toRead) { | 215 if (len < toRead) { |
| 213 toRead = len; | 216 toRead = len; |
| 214 } | 217 } |
| 215 } | 218 } |
| 216 List<int> result = buffer.data.getRange(buffer.start, toRead); | 219 List<int> result = buffer.data.getRange(buffer.start, toRead); |
| 217 buffer.advanceStart(toRead); | 220 buffer.advanceStart(toRead); |
| 218 _setHandlersAfterRead(); | 221 _setHandlersAfterRead(); |
| 219 return result; | 222 return result; |
| 220 } | 223 } |
| 221 | 224 |
| 222 int readList(List<int> data, int offset, int bytes) { | 225 int readList(List<int> data, int offset, int bytes) { |
| 223 if (_closedRead) { | 226 if (_closedRead) { |
| 224 throw new SocketException("Reading from a closed socket"); | 227 throw new SocketIOException("Reading from a closed socket"); |
| 225 } | 228 } |
| 226 if (offset < 0 || bytes < 0 || offset + bytes > data.length) { | 229 if (offset < 0 || bytes < 0 || offset + bytes > data.length) { |
| 227 throw new ArgumentError( | 230 throw new ArgumentError( |
| 228 "Invalid offset or bytes in SecureSocket.readList"); | 231 "Invalid offset or bytes in SecureSocket.readList"); |
| 229 } | 232 } |
| 230 if (_status != CONNECTED && _status != CLOSED) { | 233 if (_status != CONNECTED && _status != CLOSED) { |
| 231 return 0; | 234 return 0; |
| 232 } | 235 } |
| 233 | 236 |
| 234 int bytesRead = 0; | 237 int bytesRead = 0; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 248 | 251 |
| 249 _setHandlersAfterRead(); | 252 _setHandlersAfterRead(); |
| 250 return bytesRead; | 253 return bytesRead; |
| 251 } | 254 } |
| 252 | 255 |
| 253 // Write the data to the socket, and flush it as much as possible | 256 // Write the data to the socket, and flush it as much as possible |
| 254 // until it would block. If the write would block, _writeEncryptedData sets | 257 // until it would block. If the write would block, _writeEncryptedData sets |
| 255 // up handlers to flush the pipeline when possible. | 258 // up handlers to flush the pipeline when possible. |
| 256 int writeList(List<int> data, int offset, int bytes) { | 259 int writeList(List<int> data, int offset, int bytes) { |
| 257 if (_closedWrite) { | 260 if (_closedWrite) { |
| 258 throw new SocketException("Writing to a closed socket"); | 261 throw new SocketIOException("Writing to a closed socket"); |
| 259 } | 262 } |
| 260 if (_status != CONNECTED) return 0; | 263 if (_status != CONNECTED) return 0; |
| 261 var buffer = _secureFilter.buffers[WRITE_PLAINTEXT]; | 264 var buffer = _secureFilter.buffers[WRITE_PLAINTEXT]; |
| 262 if (bytes > buffer.free) { | 265 if (bytes > buffer.free) { |
| 263 bytes = buffer.free; | 266 bytes = buffer.free; |
| 264 } | 267 } |
| 265 if (bytes > 0) { | 268 if (bytes > 0) { |
| 266 buffer.data.setRange(buffer.start + buffer.length, bytes, data, offset); | 269 buffer.data.setRange(buffer.start + buffer.length, bytes, data, offset); |
| 267 buffer.length += bytes; | 270 buffer.length += bytes; |
| 268 } | 271 } |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 291 // We must be able to set onWrite from the onWrite callback. | 294 // We must be able to set onWrite from the onWrite callback. |
| 292 var handler = _socketWriteHandler; | 295 var handler = _socketWriteHandler; |
| 293 // Reset the one-shot handler. | 296 // Reset the one-shot handler. |
| 294 _socketWriteHandler = null; | 297 _socketWriteHandler = null; |
| 295 handler(); | 298 handler(); |
| 296 } | 299 } |
| 297 } | 300 } |
| 298 | 301 |
| 299 void _secureDataHandler() { | 302 void _secureDataHandler() { |
| 300 if (_status == HANDSHAKE) { | 303 if (_status == HANDSHAKE) { |
| 301 _secureHandshake(); | 304 try { |
| 305 _secureHandshake(); | |
| 306 } catch (e) { _reportError(e, "SecureSocket error"); } | |
| 302 } else { | 307 } else { |
| 303 _writeEncryptedData(); // TODO(whesse): Removing this causes a failure. | 308 try { |
| 304 _readEncryptedData(); | 309 _writeEncryptedData(); // TODO(whesse): Removing this causes a failure. |
| 310 _readEncryptedData(); | |
| 311 } catch (e) { _reportError(e, "SecureSocket error"); } | |
| 305 if (!_filterReadEmpty) { | 312 if (!_filterReadEmpty) { |
| 306 // Call the onData event. | 313 // Call the onData event. |
| 307 if (scheduledDataEvent != null) { | 314 if (scheduledDataEvent != null) { |
| 308 scheduledDataEvent.cancel(); | 315 scheduledDataEvent.cancel(); |
| 309 scheduledDataEvent = null; | 316 scheduledDataEvent = null; |
| 310 } | 317 } |
| 311 if (_socketDataHandler != null) { | 318 if (_socketDataHandler != null) { |
| 312 _socketDataHandler(); | 319 _socketDataHandler(); |
| 313 } | 320 } |
| 314 } | 321 } |
| 315 } | 322 } |
| 316 } | 323 } |
| 317 | 324 |
| 318 void _secureErrorHandler(e) { | 325 void _secureErrorHandler(e) { |
| 319 _reportError(e, 'Error on underlying Socket'); | 326 _reportError(e, 'Error on underlying Socket'); |
| 320 } | 327 } |
| 321 | 328 |
| 322 void _reportError(error, String message) { | 329 void _reportError(error, String message) { |
| 323 // TODO(whesse): Call _reportError from all internal functions that throw. | 330 // TODO(whesse): Call _reportError from all internal functions that throw. |
| 324 var e; | 331 var e; |
| 325 if (error is SocketIOException) { | 332 if (error is SocketIOException) { |
| 326 e = new SocketIOException('$message (${error.message})', error.osError); | 333 e = new SocketIOException('$message (${error.message})', error.osError); |
| 327 } else if (error is OSError) { | 334 } else if (error is OSError) { |
| 328 e = new SocketIOException(message, error); | 335 e = new SocketIOException(message, error); |
| 329 } else { | 336 } else { |
| 330 e = new SocketIOException('$message (${error.toString()})', null); | 337 e = new SocketIOException('$message (${error.toString()})', null); |
| 331 } | 338 } |
| 339 close(false); | |
| 332 bool reported = false; | 340 bool reported = false; |
| 333 if (_socketErrorHandler != null) { | 341 if (_socketErrorHandler != null) { |
| 334 reported = true; | 342 reported = true; |
| 335 _socketErrorHandler(e); | 343 _socketErrorHandler(e); |
| 336 } | 344 } |
| 337 if (_inputStream != null) { | 345 if (_inputStream != null) { |
| 338 reported = reported || _inputStream._onSocketError(e); | 346 reported = reported || _inputStream._onSocketError(e); |
| 339 } | 347 } |
| 340 if (_outputStream != null) { | 348 if (_outputStream != null) { |
| 341 reported = reported || _outputStream._onSocketError(e); | 349 reported = reported || _outputStream._onSocketError(e); |
| 342 } | 350 } |
| 343 | |
| 344 if (!reported) throw e; | 351 if (!reported) throw e; |
| 345 } | 352 } |
| 346 | 353 |
| 347 void _secureCloseHandler() { | 354 void _secureCloseHandler() { |
| 348 _socketClosedRead = true; | 355 _socketClosedRead = true; |
| 349 if (_filterReadEmpty) { | 356 if (_filterReadEmpty) { |
| 350 _closedRead = true; | 357 _closedRead = true; |
| 351 _fireCloseEvent(); | 358 _fireCloseEvent(); |
| 352 if (_socketClosedWrite) { | 359 if (_socketClosedWrite) { |
| 353 _secureFilter.destroy(); | 360 _secureFilter.destroy(); |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 561 bool is_server, | 568 bool is_server, |
| 562 String certificateName); | 569 String certificateName); |
| 563 void destroy(); | 570 void destroy(); |
| 564 void handshake(); | 571 void handshake(); |
| 565 void init(); | 572 void init(); |
| 566 int processBuffer(int bufferIndex); | 573 int processBuffer(int bufferIndex); |
| 567 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler); | 574 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler); |
| 568 | 575 |
| 569 List<_ExternalBuffer> get buffers; | 576 List<_ExternalBuffer> get buffers; |
| 570 } | 577 } |
| OLD | NEW |