Support for SSL/TLS ('wss://') on both sides.
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.
This commit is contained in:
parent
ca5785f570
commit
adfe6ac166
16
README.md
16
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
|
||||
-----
|
||||
|
4
TODO
4
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.
|
||||
|
Binary file not shown.
1
include/web-socket-js/WebSocketMain.swf
Symbolic link
1
include/web-socket-js/WebSocketMain.swf
Symbolic link
@ -0,0 +1 @@
|
||||
flash-src/WebSocketMain.swf
|
@ -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) {
|
||||
|
BIN
include/web-socket-js/flash-src/WebSocketMain.swf
Normal file
BIN
include/web-socket-js/flash-src/WebSocketMain.swf
Normal file
Binary file not shown.
1
include/web-socket-js/flash-src/com/hurlant
Symbolic link
1
include/web-socket-js/flash-src/com/hurlant
Symbolic link
@ -0,0 +1 @@
|
||||
../../../as3crypto_patched/src/com/hurlant
|
21
links
Normal file
21
links
Normal file
@ -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
vnc.html
2
vnc.html
@ -7,6 +7,7 @@
|
||||
Host: <input id='host' style='width:100'>
|
||||
Port: <input id='port' style='width:50'>
|
||||
Password: <input id='password' type='password' style='width:80'>
|
||||
Encrypt: <input id='encrypt' type='checkbox'>
|
||||
<input id='connectButton' type='button' value='Loading'
|
||||
style='width:100px' disabled>
|
||||
<br><br>
|
||||
@ -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>
|
||||
|
6
vnc.js
6
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";
|
||||
}
|
||||
|
53
webs.py
Executable file
53
webs.py
Executable file
@ -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
wsproxy.py
11
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"
|
||||
|
Loading…
Reference in New Issue
Block a user