libwebsocketsのサンプルでSSL通信を試す。
まず、libwebsocketsのサンプルで試してみます。
SSL通信によりサンプルサーバーを動作させるにはconfigureにオプションを付加してMakefileを作ります。
$./congifure --enable-openssl $ make clean $ make && sudo make install
test-serverにあるlibwebsockets-test-serverを起動します。
SSL通信を有効にするにはパラメータ付きで起動させます。
$ ./libwebsockets-test-server -h Usage: test-server [--port=<p>] [--ssl] [-d <log bitfield>]
起動
$ ./libwebsockets-test-server --ssl lwsts[25447]: libwebsockets test server - (C) Copyright 2010-2013 Andy Green <andy@warmcat.com> - licensed under LGPL2.1 lwsts[25447]: Initial logging level 7 lwsts[25447]: Library version: 1.2 lwsts[25447]: Started with daemon pid 0 lwsts[25447]: static allocation: 5472 + (12 x 1024 fds) = 17760 bytes lwsts[25447]: canonical_hostname = ubuntu lwsts[25447]: Compiled with OpenSSL support lwsts[25447]: Using SSL mode lwsts[25447]: per-conn mem: 184 + 1328 headers + protocol rx buf lwsts[25447]: Listening on port 7681
ブラウザからアクセスしてみる。
httpsでアクセスします。サンプルの認証鍵を使用しているので、ブラウザが信頼されないサイト、とか、セキュリティ証明書に問題あるとかいわれますが、続行して接続してみます。
※ちなみに、IE10ではHTMLは表示されますが、WebSocketの部分は動作しませんでした。たぶんセキュリティかなぁ。
その2のチャットサーバーをSSL通信化。
その2で作成したチャットソフトをSSL通信化させてみます。SSLの認証関連が面倒なので、サンプルサーバー同様、Webサーバー経由でhtmlをロードさせてからhtmlの中でWebSocketを使ってみます。
今回の実行環境
Ubuntu 12.04 LTS
Apache/2.2.22
OpenSSL 1.0.1
Windows7(クライアント実行環境)
apache2+SSLの準備
apache2+SSLを設定し、そこで設定した認証鍵をWebSocketサーバーで使用したいと思います。
今回はテストなのでSSL通信に必要な設定はサンプル等を使用します。
apache2+SSLのデフォルト設定を使用。
$ sudo aptitude -y install apache2 $ sudo a2enmod ssl $ sudo a2ensite default-ssl $ sudo /etc/init.d/apache2 restart
default-sslが使用する鍵のパス
設定ファイル:/etc/apache2/sites-available/default-ssl
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
チャットフォームの設置
DocumentRoot(/var/www)にhtmlファイルを保存します。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>WebSocket Sample</title> </head> <body> <div class="page"> <header> <div id="title"> <h1>Chat</h1> </div> </header> <section id="main"> URI <input id="uri" type="text" /> <input type="button" value="Connect" onClick="connect()" /><br> SEND<input id="chatmessage" type="text" /> <input type="button" value="Send" onClick="send()" /> <hr /> <div id="log"></div> <script type="text/javascript"> var ws; function connect(){ if ("WebSocket" in window) { ws = new WebSocket(document.querySelector("#uri").value); } else if ("MozWebSocket" in window) { ws = new MozWebSocket(document.querySelector("#uri").value); } ws.onmessage = function(event){ output(event.data); } ws.onopen = function(event){ output("WebSocket Open!"); } ws.onclose = function(event){ output("WebSocket Close."); } } function send(){ var str = document.querySelector("#chatmessage"); ws.send(str.value); str.value=""; } function disconnect(){ ws.close(); ws = null; } function output(str) { document.getElementById("log").innerHTML += str + "<hr />"; } </script> </section> <footer> </footer> </div> </body> </html>
サーバー側の改修は楽。
ソース
int main() { int n = 0; struct libwebsocket_context *context; int opts = 0; char interface_name[128] = ""; const char *iface = NULL; int syslog_options = LOG_PID | LOG_PERROR; unsigned int oldus = 0; struct lws_context_creation_info info; int debug_level = 7; memset(&info, 0, sizeof info); info.port = 7681; lws_set_log_level(debug_level, lwsl_emit_syslog); info.iface = iface; info.protocols = protocols; // info.ssl_cert_filepath = NULL; // info.ssl_private_key_filepath = NULL; info.ssl_cert_filepath = "/etc/ssl/certs/ssl-cert-snakeoil.pem"; info.ssl_private_key_filepath = "/etc/ssl/private/ssl-cert-snakeoil.key"; info.gid = -1; info.uid = -1; info.options = opts; signal(SIGINT, sighandler); setlogmask(LOG_UPTO (LOG_DEBUG)); openlog("lwsts", syslog_options, LOG_DAEMON); lwsl_notice("libwebsockets chat server -\n"); context = libwebsocket_create_context(&info); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } n = 0; while (n >= 0 && !force_exit) { struct timeval tv; gettimeofday(&tv, NULL); n = libwebsocket_service(context, 50); } libwebsocket_context_destroy(context); lwsl_notice("libwebsockets-test-server exited cleanly\n"); return 0; }
SSL通信を有効にするにはlws_context_creation_info構造体に認証鍵を指定するだけのようです。
info.ssl_cert_filepath = "/etc/ssl/certs/ssl-cert-snakeoil.pem"; info.ssl_private_key_filepath = "/etc/ssl/private/ssl-cert-snakeoil.key";
コンパイル。
$g++ cppserver.cpp -lwebsockets -o wsserver_ssl
起動してみる。尚、デフォルトではSSL通信用の認証鍵のパーミッションが無いのでsudoで実行します。
$ sudo ./wsserver_ssl [sudo] password for user: lwsts[27128]: libwebsockets chat server - lwsts[27128]: Initial logging level 7 lwsts[27128]: Library version: 1.2 lwsts[27128]: Started with daemon pid 0 lwsts[27128]: static allocation: 5472 + (12 x 1024 fds) = 17760 bytes lwsts[27128]: canonical_hostname = ubuntu lwsts[27128]: Compiled with OpenSSL support lwsts[27128]: Using SSL mode lwsts[27128]: per-conn mem: 184 + 1328 headers + protocol rx buf lwsts[27128]: LWS_CALLBACK_ADD_POLL_FD lwsts[27128]: Listening on port 7681 lwsts[27128]: LWS_CALLBACK_PROTOCOL_INIT