Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
DartBot opened this issue Jan 26, 2014 · 9 comments
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-io P2 A bug or feature request we're likely to work on type-enhancement A request for a change that isn't a bug

Comments

@DartBot
Copy link

DartBot commented Jan 26, 2014

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
Copy link
Member

lrhn commented Jan 27, 2014

Added Area-IO, Triaged labels.

@sgjesse
Copy link
Contributor

sgjesse commented Jan 28, 2014

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
Copy link
Author

DartBot commented Jan 28, 2014

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
Copy link
Member

kevmoo commented May 14, 2014

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

@DartBot
Copy link
Author

DartBot commented Oct 8, 2014

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
Copy link
Contributor

sgjesse commented Oct 9, 2014

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.

@kevmoo kevmoo added the area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. label Jun 16, 2015
@kevmoo kevmoo added P2 A bug or feature request we're likely to work on type-enhancement A request for a change that isn't a bug and removed triaged labels Mar 1, 2016
@jamespet77
Copy link

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
Copy link

neaplus commented Jul 21, 2019

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

@EP-u-NW
Copy link

EP-u-NW commented Oct 11, 2021

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-io P2 A bug or feature request we're likely to work on type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

6 participants