dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.09k stars 1.56k forks source link

dart:io WebSocket needs OnBadCertificate() callback for wss:// socket connections #16300

Open DartBot opened 10 years ago

DartBot commented 10 years ago

This issue was originally filed by j.m.sloc...@gmail.com


Using Dart VM version: 1.1.1 (Wed Jan 15 04:11:49 2014) on "linux_x64" The following dart program starts a secure HTTP server and waits for a websocket connection

import 'dart:io';

void main(List<String> args){   String password = new File('pwdfile').readAsStringSync().trim();

  SecureSocket.initialize(database: "./",                           password: password);

  HttpServer.bindSecure(InternetAddress.ANY_IP_V4, 4443,       certificateName: "CN=devcert")     .then((HttpServer server) {       print("Secure server listening on 4443...");       server.serverHeader = "Secure WebSocket server";

      server.listen((HttpRequest request) {         if (request.headers.value(HttpHeaders.UPGRADE) == "websocket"){           WebSocketTransformer.upgrade(request).then(handleWebSocket);         }         else {           request.response.statusCode = HttpStatus.FORBIDDEN;           request.response.reasonPhrase = "WebSocket connections only";           request.response.close();         }       });     }); }

void handleWebSocket(WebSocket socket){   print("Secure client connected!");   socket.listen((String s) {     print('Client sent: $s');     socket.add('echo: $s');   },   onDone: () {     print('Client disconnected');   }); }

The following program is a client that can connect to websockets.

import 'dart:io';

WebSocket ws;

void main(List<String> args){   if (args.length < 1){     print('Please specify a server URI. ex ws://example.org');     exit(1);   }

  String server = args[0];

  //Open the websocket and attach the callbacks   WebSocket.connect(server).then((WebSocket socket) {     ws = socket;     ws.listen(onMessage, onDone: connectionClosed);   });

  //Attach to stdin to read from the keyboard   stdin.listen(onInput); }

void onMessage(String message){   print(message); }

void connectionClosed() {   print('Connection to server closed'); }

void onInput(List<int> input){   String message = new String.fromCharCodes(input).trim();

  //Exit gracefully if the user types 'quit'   if (message == 'quit'){     ws.close();     exit(0);   }

  ws.add(message); }

What is the expected output? What do you see instead?

When I run this server using a self signed cert and try to connect with a client I get the following exception

$ dart secureWebSocketClient.dart wss://localhost:4443 Uncaught Error: HandshakeException: Handshake error in client (OS Error: Issuer certificate is invalid., errno = -8156) Unhandled exception: HandshakeException: Handshake error in client (OS Error: Issuer certificate is invalid., errno = -8156)

­0 _rootHandleUncaughtError.<anonymous closure>.<anonymous closure> (dart:async/zone.dart:677)

­1 _asyncRunCallback (dart:async/schedule_microtask.dart:18)

­2 _asyncRunCallback (dart:async/schedule_microtask.dart:21)

­3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:119)

However there is no way of indicating to the WebSocket class to ignore certificate errors.

The server works if I use a "plain" HTTP server, but not a secure server. It would appear that the WebSocket class should have an onBadCertificate(X509Certificate) callback like the SecureSocket classes.

lrhn commented 10 years ago

Added Area-IO, Triaged labels.

sgjesse commented 10 years ago

One way to get around this problem is to call "SecureSocket.initialize" in the client as well. The database used for the client should hold the self-signed certificate, but of-cause not the key for the server certificate. To try this out you can start with using the same database as is used for the server.

It would be possible to add a callback for handling bad server certificates when opening web socket connections, see https://codereview.chromium.org/148613005/. However I am not sure it should be added like that.


Removed Type-Defect, Priority-Unassigned labels. Added Type-Enhancement, Priority-Medium labels.

DartBot commented 10 years ago

This comment was originally written by j.m.s...@gmail.com


Yes that worked! I will add for anyone else looking into this though that the CN must be the same as the hostname in the wss:// URI. So if you want to connect to wss://localhost/ you need a certificate with the CN=localhost or you get the following exception.

$ dart secureWebSocketClient.dart wss://localhost:4443 Uncaught Error: HandshakeException: Handshake error in client (OS Error: Unable to communicate securely with peer: requested domain name does not match the server's certificate., errno = -12276) Unhandled exception: HandshakeException: Handshake error in client (OS Error: Unable to communicate securely with peer: requested domain name does not match the server's certificate., errno = -12276)

­0 _rootHandleUncaughtError.<anonymous closure>.<anonymous closure> (dart:async/zone.dart:677)

­1 _asyncRunCallback (dart:async/schedule_microtask.dart:18)

­2 _asyncRunCallback (dart:async/schedule_microtask.dart:21)

­3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:119)

kevmoo commented 10 years ago

Removed Area-IO label. Added Library-IO label.

DartBot commented 9 years ago

This comment was originally written by @almstrand


SecureSocket is defined in dart:io and since dart:io is not available for webapps, calling SecureDocket.initialize is not an option for most applications.

Per the original post, adding an onBadCertificate() callback to the WebSocket class (similar to the SecureSocket class) seems like a good solution.

sgjesse commented 9 years ago

When in the browser the certificate handling is done by the browser. Different browsers might handle this differently, but most likely you will have to install a CA certificate into the browsers certificate store.

jamespet77 commented 6 years ago

Has this been addressed? I am having an issue where I need to accept a self signed cert and this is holding me up.

neaplus commented 5 years ago

after 5 years, this is still open. A solution needed.

EP-u-NW commented 2 years ago

At least for the dart:io version of websockets, an onBadCertificate() would be great!