| 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 // VMOptions= | 5 // VMOptions= |
| 6 // VMOptions=--short_socket_read | 6 // VMOptions=--short_socket_read |
| 7 // VMOptions=--short_socket_write | 7 // VMOptions=--short_socket_write |
| 8 // VMOptions=--short_socket_read --short_socket_write | 8 // VMOptions=--short_socket_read --short_socket_write |
| 9 | 9 |
| 10 import "dart:async"; | 10 import "dart:async"; |
| 11 import "dart:io"; | 11 import "dart:io"; |
| 12 | 12 |
| 13 import "package:async_helper/async_helper.dart"; | 13 import "package:async_helper/async_helper.dart"; |
| 14 import "package:expect/expect.dart"; | 14 import "package:expect/expect.dart"; |
| 15 | 15 |
| 16 InternetAddress HOST; | 16 InternetAddress HOST; |
| 17 const CERTIFICATE = "localhost_cert"; | 17 String localFile(path) => Platform.script.resolve(path).toFilePath(); |
| 18 |
| 19 SecurityContext serverContext = new SecurityContext() |
| 20 ..useCertificateChain(localFile('certificates/server_chain.pem')) |
| 21 ..usePrivateKey(localFile('certificates/server_key.pem'), |
| 22 password: 'dartdart'); |
| 23 |
| 24 SecurityContext clientContext = new SecurityContext() |
| 25 ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem')); |
| 18 | 26 |
| 19 void testSimpleBind() { | 27 void testSimpleBind() { |
| 20 asyncStart(); | 28 asyncStart(); |
| 21 RawSecureServerSocket.bind(HOST, 0, CERTIFICATE).then((s) { | 29 RawSecureServerSocket.bind(HOST, 0, serverContext).then((s) { |
| 22 Expect.isTrue(s.port > 0); | 30 Expect.isTrue(s.port > 0); |
| 23 s.close(); | 31 s.close(); |
| 24 asyncEnd(); | 32 asyncEnd(); |
| 25 }); | 33 }); |
| 26 } | 34 } |
| 27 | 35 |
| 28 void testInvalidBind() { | 36 void testInvalidBind() { |
| 29 int count = 0; | 37 int count = 0; |
| 30 | 38 |
| 31 // Bind to a unknown DNS name. | 39 // Bind to a unknown DNS name. |
| 32 asyncStart(); | 40 asyncStart(); |
| 33 RawSecureServerSocket.bind("ko.faar.__hest__", 0, CERTIFICATE).then((_) { | 41 RawSecureServerSocket.bind("ko.faar.__hest__", 0, serverContext).then((_) { |
| 34 Expect.fail("Failure expected"); | 42 Expect.fail("Failure expected"); |
| 35 }).catchError((error) { | 43 }).catchError((error) { |
| 36 Expect.isTrue(error is SocketException); | 44 Expect.isTrue(error is SocketException); |
| 37 asyncEnd(); | 45 asyncEnd(); |
| 38 }); | 46 }); |
| 39 | 47 |
| 40 // Bind to an unavaliable IP-address. | 48 // Bind to an unavaliable IP-address. |
| 41 asyncStart(); | 49 asyncStart(); |
| 42 RawSecureServerSocket.bind("8.8.8.8", 0, CERTIFICATE).then((_) { | 50 RawSecureServerSocket.bind("8.8.8.8", 0, serverContext).then((_) { |
| 43 Expect.fail("Failure expected"); | 51 Expect.fail("Failure expected"); |
| 44 }).catchError((error) { | 52 }).catchError((error) { |
| 45 Expect.isTrue(error is SocketException); | 53 Expect.isTrue(error is SocketException); |
| 46 asyncEnd(); | 54 asyncEnd(); |
| 47 }); | 55 }); |
| 48 | 56 |
| 49 // Bind to a port already in use. | 57 // Bind to a port already in use. |
| 50 asyncStart(); | 58 asyncStart(); |
| 51 RawSecureServerSocket.bind(HOST, 0, CERTIFICATE).then((s) { | 59 RawSecureServerSocket.bind(HOST, 0, serverContext).then((s) { |
| 52 RawSecureServerSocket.bind(HOST, | 60 RawSecureServerSocket.bind(HOST, |
| 53 s.port, | 61 s.port, |
| 54 CERTIFICATE).then((t) { | 62 serverContext).then((t) { |
| 55 s.close(); | 63 s.close(); |
| 56 t.close(); | 64 t.close(); |
| 57 Expect.fail("Multiple listens on same port"); | 65 Expect.fail("Multiple listens on same port"); |
| 58 }) | 66 }) |
| 59 .catchError((error) { | 67 .catchError((error) { |
| 60 Expect.isTrue(error is SocketException); | 68 Expect.isTrue(error is SocketException); |
| 61 s.close(); | 69 s.close(); |
| 62 asyncEnd(); | 70 asyncEnd(); |
| 63 }); | 71 }); |
| 64 }); | 72 }); |
| 65 } | 73 } |
| 66 | 74 |
| 67 void testSimpleConnect(String certificate) { | 75 void testSimpleConnect() { |
| 68 asyncStart(); | 76 asyncStart(); |
| 69 RawSecureServerSocket.bind(HOST, 0, certificate).then((server) { | 77 RawSecureServerSocket.bind(HOST, 0, serverContext).then((server) { |
| 70 var clientEndFuture = RawSecureSocket.connect(HOST, server.port); | 78 var clientEndFuture = |
| 79 RawSecureSocket.connect(HOST, server.port, context: clientContext); |
| 71 server.listen((serverEnd) { | 80 server.listen((serverEnd) { |
| 72 clientEndFuture.then((clientEnd) { | 81 clientEndFuture.then((clientEnd) { |
| 82 // TODO(whesse): Shutdown(SEND) not supported on secure sockets. |
| 73 clientEnd.shutdown(SocketDirection.SEND); | 83 clientEnd.shutdown(SocketDirection.SEND); |
| 74 serverEnd.shutdown(SocketDirection.SEND); | 84 serverEnd.shutdown(SocketDirection.SEND); |
| 75 server.close(); | 85 server.close(); |
| 76 asyncEnd(); | 86 asyncEnd(); |
| 77 }); | 87 }); |
| 78 }); | 88 }); |
| 79 }); | 89 }); |
| 80 } | 90 } |
| 81 | 91 |
| 82 void testSimpleConnectFail(String certificate, bool cancelOnError) { | 92 void testSimpleConnectFail(SecurityContext context, bool cancelOnError) { |
| 83 asyncStart(); | 93 asyncStart(); |
| 84 RawSecureServerSocket.bind(HOST, 0, certificate).then((server) { | 94 RawSecureServerSocket.bind(HOST, 0, context).then((server) { |
| 85 var clientEndFuture = RawSecureSocket.connect(HOST, server.port) | 95 var clientEndFuture = |
| 96 RawSecureSocket.connect(HOST, server.port, context: clientContext) |
| 86 .then((clientEnd) { | 97 .then((clientEnd) { |
| 87 Expect.fail("No client connection expected."); | 98 Expect.fail("No client connection expected."); |
| 88 }) | 99 }) |
| 89 .catchError((error) { | 100 .catchError((error) { |
| 90 Expect.isTrue(error is SocketException || | 101 Expect.isTrue(error is SocketException || |
| 91 error is HandshakeException); | 102 error is HandshakeException); |
| 92 }); | 103 }); |
| 93 server.listen((serverEnd) { | 104 server.listen((serverEnd) { |
| 94 Expect.fail("No server connection expected."); | 105 Expect.fail("No server connection expected."); |
| 95 }, | 106 }, |
| 96 onError: (error) { | 107 onError: (error) { |
| 97 Expect.isTrue(error is CertificateException); | 108 Expect.isTrue(error is HandshakeException); |
| 98 clientEndFuture.then((_) { | 109 clientEndFuture.then((_) { |
| 99 if (!cancelOnError) server.close(); | 110 if (!cancelOnError) server.close(); |
| 100 asyncEnd(); | 111 asyncEnd(); |
| 101 }); | 112 }); |
| 102 }, | 113 }, |
| 103 cancelOnError: cancelOnError); | 114 cancelOnError: cancelOnError); |
| 104 }); | 115 }); |
| 105 } | 116 } |
| 106 | 117 |
| 107 void testServerListenAfterConnect() { | 118 void testServerListenAfterConnect() { |
| 108 asyncStart(); | 119 asyncStart(); |
| 109 RawSecureServerSocket.bind(HOST, 0, CERTIFICATE).then((server) { | 120 RawSecureServerSocket.bind(HOST, 0, serverContext).then((server) { |
| 110 Expect.isTrue(server.port > 0); | 121 Expect.isTrue(server.port > 0); |
| 111 var clientEndFuture = RawSecureSocket.connect(HOST, server.port); | 122 var clientEndFuture = |
| 123 RawSecureSocket.connect(HOST, server.port, context: clientContext); |
| 112 new Timer(const Duration(milliseconds: 500), () { | 124 new Timer(const Duration(milliseconds: 500), () { |
| 113 server.listen((serverEnd) { | 125 server.listen((serverEnd) { |
| 114 clientEndFuture.then((clientEnd) { | 126 clientEndFuture.then((clientEnd) { |
| 115 clientEnd.shutdown(SocketDirection.SEND); | 127 clientEnd.shutdown(SocketDirection.SEND); |
| 116 serverEnd.shutdown(SocketDirection.SEND); | 128 serverEnd.shutdown(SocketDirection.SEND); |
| 117 server.close(); | 129 server.close(); |
| 118 asyncEnd(); | 130 asyncEnd(); |
| 119 }); | 131 }); |
| 120 }); | 132 }); |
| 121 }); | 133 }); |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 Expect.fail("Unexpected close"); | 427 Expect.fail("Unexpected close"); |
| 416 break; | 428 break; |
| 417 default: throw "Unexpected event $event"; | 429 default: throw "Unexpected event $event"; |
| 418 } | 430 } |
| 419 }); | 431 }); |
| 420 return completer.future; | 432 return completer.future; |
| 421 } | 433 } |
| 422 | 434 |
| 423 Future<RawSecureSocket> connectClient(int port) { | 435 Future<RawSecureSocket> connectClient(int port) { |
| 424 if (connectSecure) { | 436 if (connectSecure) { |
| 425 return RawSecureSocket.connect(HOST, port); | 437 return RawSecureSocket.connect(HOST, port, context: clientContext); |
| 426 } else if (!handshakeBeforeSecure) { | 438 } else if (!handshakeBeforeSecure) { |
| 427 return RawSocket.connect(HOST, port).then((socket) { | 439 return RawSocket.connect(HOST, port).then((socket) { |
| 428 return RawSecureSocket.secure(socket); | 440 return RawSecureSocket.secure(socket, context: clientContext); |
| 429 }); | 441 }); |
| 430 } else { | 442 } else { |
| 431 return RawSocket.connect(HOST, port).then((socket) { | 443 return RawSocket.connect(HOST, port).then((socket) { |
| 432 return runClientHandshake(socket).then((subscription) { | 444 return runClientHandshake(socket).then((subscription) { |
| 433 return RawSecureSocket.secure(socket, subscription: subscription); | 445 return RawSecureSocket.secure(socket, |
| 446 context: clientContext, |
| 447 subscription: subscription); |
| 434 }); | 448 }); |
| 435 }); | 449 }); |
| 436 } | 450 } |
| 437 } | 451 } |
| 438 | 452 |
| 439 serverReady(server) { | 453 serverReady(server) { |
| 440 server.listen((client) { | 454 server.listen((client) { |
| 441 if (listenSecure) { | 455 if (listenSecure) { |
| 442 runServer(client).then((_) => server.close()); | 456 runServer(client).then((_) => server.close()); |
| 443 } else if (!handshakeBeforeSecure) { | 457 } else if (!handshakeBeforeSecure) { |
| 444 RawSecureSocket.secureServer(client, CERTIFICATE).then((client) { | 458 RawSecureSocket.secureServer(client, serverContext).then((client) { |
| 445 runServer(client).then((_) => server.close()); | 459 runServer(client).then((_) => server.close()); |
| 446 }); | 460 }); |
| 447 } else { | 461 } else { |
| 448 runServerHandshake(client).then((secure) { | 462 runServerHandshake(client).then((secure) { |
| 449 RawSecureSocket.secureServer( | 463 RawSecureSocket.secureServer( |
| 450 client, | 464 client, |
| 451 CERTIFICATE, | 465 serverContext, |
| 452 subscription: secure[0], | 466 subscription: secure[0], |
| 453 bufferedData: secure[1]).then((client) { | 467 bufferedData: secure[1]).then((client) { |
| 454 runServer(client).then((_) => server.close()); | 468 runServer(client).then((_) => server.close()); |
| 455 }); | 469 }); |
| 456 }); | 470 }); |
| 457 } | 471 } |
| 458 }); | 472 }); |
| 459 | 473 |
| 460 connectClient(server.port).then(runClient).then((socket) { | 474 connectClient(server.port).then(runClient).then((socket) { |
| 461 socket.close(); | 475 socket.close(); |
| 462 asyncEnd(); | 476 asyncEnd(); |
| 463 }); | 477 }); |
| 464 } | 478 } |
| 465 | 479 |
| 466 if (listenSecure) { | 480 if (listenSecure) { |
| 467 RawSecureServerSocket.bind( | 481 RawSecureServerSocket.bind( |
| 468 HOST, 0, CERTIFICATE).then(serverReady); | 482 HOST, 0, serverContext).then(serverReady); |
| 469 } else { | 483 } else { |
| 470 RawServerSocket.bind(HOST, 0).then(serverReady); | 484 RawServerSocket.bind(HOST, 0).then(serverReady); |
| 471 } | 485 } |
| 472 } | 486 } |
| 473 | 487 |
| 474 testPausedSecuringSubscription(bool pausedServer, bool pausedClient) { | 488 testPausedSecuringSubscription(bool pausedServer, bool pausedClient) { |
| 475 asyncStart(); | 489 asyncStart(); |
| 476 var clientComplete = new Completer(); | 490 var clientComplete = new Completer(); |
| 477 RawServerSocket.bind(HOST, 0).then((server) { | 491 RawServerSocket.bind(HOST, 0).then((server) { |
| 478 server.listen((client) { | 492 server.listen((client) { |
| 479 var subscription; | 493 var subscription; |
| 480 subscription = client.listen((_) { | 494 subscription = client.listen((_) { |
| 481 if (pausedServer) { | 495 if (pausedServer) { |
| 482 subscription.pause(); | 496 subscription.pause(); |
| 483 } | 497 } |
| 484 void done() { | 498 void done() { |
| 485 server.close(); | 499 server.close(); |
| 486 clientComplete.future.then((_) { | 500 clientComplete.future.then((_) { |
| 487 client.close(); | 501 client.close(); |
| 488 asyncEnd(); | 502 asyncEnd(); |
| 489 }); | 503 }); |
| 490 } | 504 } |
| 491 try { | 505 try { |
| 492 RawSecureSocket.secureServer( | 506 RawSecureSocket.secureServer( |
| 493 client, CERTIFICATE, subscription: subscription) | 507 client, serverContext, subscription: subscription) |
| 494 .catchError((_) {}) | 508 .catchError((_) {}) |
| 495 .whenComplete(() { | 509 .whenComplete(() { |
| 496 if (pausedServer) { | 510 if (pausedServer) { |
| 497 Expect.fail("secureServer succeeded with paused subscription"); | 511 Expect.fail("secureServer succeeded with paused subscription"); |
| 498 } | 512 } |
| 499 done(); | 513 done(); |
| 500 }); | 514 }); |
| 501 } catch (e) { | 515 } catch (e) { |
| 502 if (!pausedServer) { | 516 if (!pausedServer) { |
| 503 Expect.fail("secureServer failed with non-paused subscriptions"); | 517 Expect.fail("secureServer failed with non-paused subscriptions"); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 536 } | 550 } |
| 537 clientComplete.complete(null); | 551 clientComplete.complete(null); |
| 538 } | 552 } |
| 539 }); | 553 }); |
| 540 }); | 554 }); |
| 541 }); | 555 }); |
| 542 } | 556 } |
| 543 | 557 |
| 544 main() { | 558 main() { |
| 545 asyncStart(); | 559 asyncStart(); |
| 546 var certificateDatabase = Platform.script.resolve('pkcert').toFilePath(); | |
| 547 SecureSocket.initialize(database: certificateDatabase, | |
| 548 password: 'dartdart', | |
| 549 useBuiltinRoots: false); | |
| 550 InternetAddress.lookup("localhost").then((hosts) { | 560 InternetAddress.lookup("localhost").then((hosts) { |
| 551 HOST = hosts.first; | 561 HOST = hosts.first; |
| 552 runTests(); | 562 runTests(); |
| 553 asyncEnd(); | 563 asyncEnd(); |
| 554 }); | 564 }); |
| 555 } | 565 } |
| 556 | 566 |
| 557 runTests() { | 567 runTests() { |
| 558 testSimpleBind(); | 568 testSimpleBind(); |
| 559 testInvalidBind(); | 569 testInvalidBind(); |
| 560 testSimpleConnect(CERTIFICATE); | 570 testSimpleConnect(); |
| 561 testSimpleConnect("CN=localhost"); | 571 SecurityContext context = new SecurityContext(); |
| 562 testSimpleConnectFail("not_a_nickname", false); | 572 testSimpleConnectFail(context, false); |
| 563 testSimpleConnectFail("CN=notARealDistinguishedName", false); | 573 testSimpleConnectFail(context, true); |
| 564 testSimpleConnectFail("not_a_nickname", true); | 574 var chain = |
| 565 testSimpleConnectFail("CN=notARealDistinguishedName", true); | 575 Platform.script.resolve('certificates/untrusted_server_chain.pem') |
| 576 .toFilePath(); |
| 577 context.useCertificateChain(chain); |
| 578 testSimpleConnectFail(context, false); |
| 579 testSimpleConnectFail(context, true); |
| 580 var key = |
| 581 Platform.script.resolve('certificates/untrusted_server_key.pem') |
| 582 .toFilePath(); |
| 583 context.usePrivateKey(key, password: 'dartdart'); |
| 584 testSimpleConnectFail(context, false); |
| 585 testSimpleConnectFail(context, true); |
| 566 testServerListenAfterConnect(); | 586 testServerListenAfterConnect(); |
| 567 | 587 |
| 568 testSimpleReadWrite(listenSecure: true, | 588 testSimpleReadWrite(listenSecure: true, |
| 569 connectSecure: true, | 589 connectSecure: true, |
| 570 handshakeBeforeSecure: false, | 590 handshakeBeforeSecure: false, |
| 571 postponeSecure: false, | 591 postponeSecure: false, |
| 572 dropReads: false); | 592 dropReads: false); |
| 573 testSimpleReadWrite(listenSecure: true, | 593 testSimpleReadWrite(listenSecure: true, |
| 574 connectSecure: false, | 594 connectSecure: false, |
| 575 handshakeBeforeSecure: false, | 595 handshakeBeforeSecure: false, |
| 576 postponeSecure: false, | 596 postponeSecure: false, |
| 577 dropReads: false); | 597 dropReads: false); |
| 598 |
| 578 testSimpleReadWrite(listenSecure: false, | 599 testSimpleReadWrite(listenSecure: false, |
| 579 connectSecure: true, | 600 connectSecure: true, |
| 580 handshakeBeforeSecure: false, | 601 handshakeBeforeSecure: false, |
| 581 postponeSecure: false, | 602 postponeSecure: false, |
| 582 dropReads: false); | 603 dropReads: false); |
| 604 |
| 583 testSimpleReadWrite(listenSecure: false, | 605 testSimpleReadWrite(listenSecure: false, |
| 584 connectSecure: false, | 606 connectSecure: false, |
| 585 handshakeBeforeSecure: false, | 607 handshakeBeforeSecure: false, |
| 586 postponeSecure: false, | 608 postponeSecure: false, |
| 587 dropReads: false); | 609 dropReads: false); |
| 588 testSimpleReadWrite(listenSecure: false, | 610 testSimpleReadWrite(listenSecure: false, |
| 589 connectSecure: false, | 611 connectSecure: false, |
| 590 handshakeBeforeSecure: true, | 612 handshakeBeforeSecure: true, |
| 591 postponeSecure: true, | 613 postponeSecure: true, |
| 592 dropReads: false); | 614 dropReads: false); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 603 testSimpleReadWrite(listenSecure: false, | 625 testSimpleReadWrite(listenSecure: false, |
| 604 connectSecure: false, | 626 connectSecure: false, |
| 605 handshakeBeforeSecure: true, | 627 handshakeBeforeSecure: true, |
| 606 postponeSecure: true, | 628 postponeSecure: true, |
| 607 dropReads: true); | 629 dropReads: true); |
| 608 testPausedSecuringSubscription(false, false); | 630 testPausedSecuringSubscription(false, false); |
| 609 testPausedSecuringSubscription(true, false); | 631 testPausedSecuringSubscription(true, false); |
| 610 testPausedSecuringSubscription(false, true); | 632 testPausedSecuringSubscription(false, true); |
| 611 testPausedSecuringSubscription(true, true); | 633 testPausedSecuringSubscription(true, true); |
| 612 } | 634 } |
| OLD | NEW |