Skip to content

Commit

Permalink
Support for SSL/TLS ('wss://') on both sides.
Browse files Browse the repository at this point in the history
On the client side, this adds the as3crypto library to web-socket-js
so that the WebSocket 'wss://' scheme is supported which is WebSocket
over SSL/TLS.

Couple of downsides to the fall-back method:

    - This balloons the size of the web-socket-js object from about 12K to 172K.

    - Getting it working required disabling RFC2718 web proxy support
      in web-socket-js.

    - It makes the web-socket-js fallback even slower with the
      encryption overhead.

The server side (wsproxy.py) uses python SSL support. The proxy
automatically detects the type of incoming connection whether flash
policy request, SSL/TLS handshake ('wss://') or plain socket
('ws://').

Also added a check-box to the web page to enable/disabled 'wss://'
encryption.
  • Loading branch information
kanaka committed Apr 30, 2010
1 parent ca5785f commit adfe6ac
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 14 deletions.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,24 @@ Description
-----------

A VNC client implemented using HTML5, specifically Canvas and
WebSocket.
WebSocket (supports 'wss://' encryption).

For browsers that do not have builtin WebSocket support, the project
includes web-socket-js, a WebSocket emulator using Adobe Flash
(http://github.com/gimite/web-socket-js).

In addition, as3crypto has been added to web-socket-js to implement
WebSocket SSL/TLS encryption, i.e. the "wss://" URI scheme.
(http://github.com/lyokato/as3crypto_patched).


Requirements
------------

Until there is VNC server support for WebSocket connections, you need
to use a WebSocket to TCP socket proxy. There is a python proxy
included ('wsproxy').
included ('wsproxy'). One advantage of using the proxy is that it has
builtin support for SSL/TLS encryption (i.e. "wss://").

There a few reasons why a proxy is required:

Expand All @@ -38,6 +43,13 @@ There a few reasons why a proxy is required:
the client asks the proxy (using the initial query string) to add
sequence numbers to each packet.

To encrypt the traffic using the WebSocket 'wss://' URI scheme you
need to generate a certificate for the proxy to load. You can generate
a self-signed certificate using openssl. The common name should be the
hostname of the server where the proxy will be running:

`openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem`


Usage
-----
Expand Down
4 changes: 2 additions & 2 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
- Add WSS/https/SSL support to page and wsproxy.py

- Make C version of wsproxy.py

- Implement UI option for VNC shared mode.

- Upgrade to protocol 3.8
- implement ZRLE encoding

- Get web-socket-js RFC2817 proxying working again.
Binary file removed include/web-socket-js/WebSocketMain.swf
Binary file not shown.
1 change: 1 addition & 0 deletions include/web-socket-js/WebSocketMain.swf
48 changes: 40 additions & 8 deletions include/web-socket-js/flash-src/WebSocket.as
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import mx.controls.*;
import mx.events.*;
import mx.utils.*;
import com.adobe.net.proxies.RFC2817Socket;
import com.hurlant.crypto.tls.TLSSocket;
import com.hurlant.crypto.tls.TLSConfig;
import com.hurlant.crypto.tls.TLSEngine;
import com.hurlant.crypto.tls.TLSSecurityParameters;

[Event(name="message", type="WebSocketMessageEvent")]
[Event(name="open", type="flash.events.Event")]
Expand All @@ -27,7 +31,11 @@ public class WebSocket extends EventDispatcher {
private static var OPEN:int = 1;
private static var CLOSED:int = 2;

private var socket:RFC2817Socket;
//private var rawSocket:RFC2817Socket;
private var rawSocket:Socket;
private var tlsSocket:TLSSocket;
private var tlsConfig:TLSConfig;
private var socket:Socket;
private var main:WebSocketMain;
private var scheme:String;
private var host:String;
Expand Down Expand Up @@ -59,20 +67,38 @@ public class WebSocket extends EventDispatcher {
// "Header1: xxx\r\nHeader2: yyyy\r\n"
this.headers = headers;

/*
socket = new RFC2817Socket();
// if no proxy information is supplied, it acts like a normal Socket
// @see RFC2817Socket::connect
if (proxyHost != null && proxyPort != 0){
socket.setProxyInfo(proxyHost, proxyPort);
}

socket.addEventListener(Event.CLOSE, onSocketClose);
socket.addEventListener(Event.CONNECT, onSocketConnect);
socket.addEventListener(IOErrorEvent.IO_ERROR, onSocketIoError);
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSocketSecurityError);
socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
socket.connect(host, port);
*/

ExternalInterface.call("console.log", "[WebSocket] scheme: " + scheme);
rawSocket = new Socket();

rawSocket.addEventListener(Event.CLOSE, onSocketClose);
rawSocket.addEventListener(Event.CONNECT, onSocketConnect);
rawSocket.addEventListener(IOErrorEvent.IO_ERROR, onSocketIoError);
rawSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSocketSecurityError);
if (scheme == "wss") {
tlsConfig= new TLSConfig(TLSEngine.CLIENT,
null, null, null, null, null,
TLSSecurityParameters.PROTOCOL_VERSION);
tlsConfig.trustSelfSignedCertificates = true;
tlsConfig.ignoreCommonNameMismatch = true;

tlsSocket = new TLSSocket();
tlsSocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
socket = (tlsSocket as Socket);
} else {
rawSocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
socket = (rawSocket as Socket);
}
rawSocket.connect(host, port);
}

public function send(data:String):int {
Expand Down Expand Up @@ -118,6 +144,12 @@ public class WebSocket extends EventDispatcher {

private function onSocketConnect(event:Event):void {
main.log("connected");

if (scheme == "wss") {
ExternalInterface.call("console.log", "[WebSocket] starting SSL/TLS");
tlsSocket.startTLS(rawSocket, host, tlsConfig);
}

var hostValue:String = host + (port == 80 ? "" : ":" + port);
var cookie:String = "";
if (main.getCallerHost() == host) {
Expand Down
Binary file not shown.
1 change: 1 addition & 0 deletions include/web-socket-js/flash-src/com/hurlant
21 changes: 21 additions & 0 deletions links
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Canvas Browser Compatibility:
http://philip.html5.org/tests/canvas/suite/tests/results.html

WebSockets API standard:
http://dev.w3.org/html5/websockets/

Browser Keyboard Events detailed:
http://unixpapa.com/js/key.html

ActionScript (Flash) WebSocket implementation:
http://github.com/gimite/web-socket-js

ActionScript (Flash) crypto/TLS library:
http://code.google.com/p/as3crypto
http://github.com/lyokato/as3crypto_patched

TLS Protocol:
http://en.wikipedia.org/wiki/Transport_Layer_Security

Generate self-signed certificate:
http://docs.python.org/dev/library/ssl.html#certificates
2 changes: 2 additions & 0 deletions vnc.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
Host: <input id='host' style='width:100'>&nbsp;
Port: <input id='port' style='width:50'>&nbsp;
Password: <input id='password' type='password' style='width:80'>&nbsp;
Encrypt: <input id='encrypt' type='checkbox'>&nbsp;
<input id='connectButton' type='button' value='Loading'
style='width:100px' disabled>&nbsp;
<br><br>
Expand Down Expand Up @@ -75,6 +76,7 @@
$('host').value = (url.match(/host=([^&#]*)/) || ['',''])[1];
$('port').value = (url.match(/port=([^&#]*)/) || ['',''])[1];
$('password').value = (url.match(/password=([^&#]*)/) || ['',''])[1];
$('encrypt').checked = (url.match(/encrypt=([^&#]*)/) || ['',''])[1];
}
}
</script>
Expand Down
6 changes: 5 additions & 1 deletion vnc.js
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,11 @@ updateState: function(state, statusMsg) {
init_ws: function () {

console.log(">> init_ws");
var uri = "ws://" + RFB.host + ":" + RFB.port + "/?b64encode";
var scheme = "ws://";
if ($('encrypt').checked) {
scheme = "wss://";
}
var uri = scheme + RFB.host + ":" + RFB.port + "/?b64encode";
if (RFB.use_seq) {
uri += "&seq_num";
}
Expand Down
53 changes: 53 additions & 0 deletions webs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/python
'''
A super simple HTTP/HTTPS webserver for python. Automatically detect
You can make a cert/key with openssl using:
openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
as taken from http://docs.python.org/dev/library/ssl.html#certificates
'''

import traceback, sys
import socket
import ssl
#import http.server as server # python 3.X
import SimpleHTTPServer as server # python 2.X

def do_request(connstream, from_addr):
x = object()
server.SimpleHTTPRequestHandler(connstream, from_addr, x)

def serve():
bindsocket = socket.socket()
#bindsocket.bind(('localhost', PORT))
bindsocket.bind(('', PORT))
bindsocket.listen(5)

print("serving on port", PORT)

while True:
try:
newsocket, from_addr = bindsocket.accept()
peek = newsocket.recv(1024, socket.MSG_PEEK)
if peek.startswith("\x16"):
connstream = ssl.wrap_socket(
newsocket,
server_side=True,
certfile='self.pem',
ssl_version=ssl.PROTOCOL_TLSv1)
else:
connstream = newsocket

do_request(connstream, from_addr)

except Exception:
traceback.print_exc()

try:
PORT = int(sys.argv[1])
except:
print "%s port" % sys.argv[0]
sys.exit(2)

serve()
11 changes: 10 additions & 1 deletion wsproxy.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
#!/usr/bin/python

'''
A WebSocket to TCP socket proxy with support for "wss://" encryption.
You can make a cert/key with openssl using:
openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
as taken from http://docs.python.org/dev/library/ssl.html#certificates
'''

import sys, os, socket, ssl, time, traceback, re
from base64 import b64encode, b64decode
from select import select
Expand Down Expand Up @@ -129,7 +138,7 @@ def do_handshake(sock):
retsock = ssl.wrap_socket(
sock,
server_side=True,
certfile='wsproxy.pem',
certfile='self.pem',
ssl_version=ssl.PROTOCOL_TLSv1)
scheme = "wss"
print "Using SSL/TLS"
Expand Down

0 comments on commit adfe6ac

Please sign in to comment.