diff --git a/README.md b/README.md
index e09e4cb5..efa4945f 100644
--- a/README.md
+++ b/README.md
@@ -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:
@@ -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
-----
diff --git a/TODO b/TODO
index d72e028e..e030ad6c 100644
--- a/TODO
+++ b/TODO
@@ -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.
diff --git a/include/web-socket-js/WebSocketMain.swf b/include/web-socket-js/WebSocketMain.swf
deleted file mode 100644
index 33810879..00000000
Binary files a/include/web-socket-js/WebSocketMain.swf and /dev/null differ
diff --git a/include/web-socket-js/WebSocketMain.swf b/include/web-socket-js/WebSocketMain.swf
new file mode 120000
index 00000000..4753408d
--- /dev/null
+++ b/include/web-socket-js/WebSocketMain.swf
@@ -0,0 +1 @@
+flash-src/WebSocketMain.swf
\ No newline at end of file
diff --git a/include/web-socket-js/flash-src/WebSocket.as b/include/web-socket-js/flash-src/WebSocket.as
index 39693633..40085c18 100644
--- a/include/web-socket-js/flash-src/WebSocket.as
+++ b/include/web-socket-js/flash-src/WebSocket.as
@@ -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")]
@@ -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;
@@ -59,6 +67,7 @@ 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
@@ -66,13 +75,30 @@ public class WebSocket extends EventDispatcher {
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 {
@@ -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) {
diff --git a/include/web-socket-js/flash-src/WebSocketMain.swf b/include/web-socket-js/flash-src/WebSocketMain.swf
new file mode 100644
index 00000000..91da2f8c
Binary files /dev/null and b/include/web-socket-js/flash-src/WebSocketMain.swf differ
diff --git a/include/web-socket-js/flash-src/com/hurlant b/include/web-socket-js/flash-src/com/hurlant
new file mode 120000
index 00000000..f9f4c84c
--- /dev/null
+++ b/include/web-socket-js/flash-src/com/hurlant
@@ -0,0 +1 @@
+../../../as3crypto_patched/src/com/hurlant
\ No newline at end of file
diff --git a/links b/links
new file mode 100644
index 00000000..93deb3d9
--- /dev/null
+++ b/links
@@ -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
diff --git a/vnc.html b/vnc.html
index ea66975d..c577068d 100644
--- a/vnc.html
+++ b/vnc.html
@@ -7,6 +7,7 @@
Host:
Port:
Password:
+ Encrypt:
@@ -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];
}
}
diff --git a/vnc.js b/vnc.js
index b46aaacf..cc0692d7 100644
--- a/vnc.js
+++ b/vnc.js
@@ -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";
}
diff --git a/webs.py b/webs.py
new file mode 100755
index 00000000..f0bffe20
--- /dev/null
+++ b/webs.py
@@ -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()
diff --git a/wsproxy.py b/wsproxy.py
index a1710b19..6f6296a0 100755
--- a/wsproxy.py
+++ b/wsproxy.py
@@ -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
@@ -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"