From 15e2dd96a4776cb8ed87db381c939061054cd19a Mon Sep 17 00:00:00 2001 From: Shuanglei Tao Date: Wed, 23 Nov 2016 23:19:32 +0800 Subject: [PATCH] Enable client certificate verification if ssl CA is given --- README.md | 34 ++++++++++++++++++++++++++++++---- src/http.c | 9 +++++++++ src/protocol.c | 2 +- src/server.c | 10 ++++++---- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 01878ea..58548d9 100644 --- a/README.md +++ b/README.md @@ -70,10 +70,10 @@ OPTIONS: --client-option, -t Send option to client (format: key=value), repeat to add more options --check-origin, -O Do not allow websocket connection from different origin --once, -o Accept only one client and exit on disconnection - --ssl, -S Enable ssl - --ssl-cert, -C Ssl certificate file path - --ssl-key, -K Ssl key file path - --ssl-ca, -A Ssl ca file path + --ssl, -S Enable SSL + --ssl-cert, -C SSL certificate file path + --ssl-key, -K SSL key file path + --ssl-ca, -A SSL CA file path for client certificate verification --debug, -d Set log level (0-9, default: 7) --version, -v Print the version and exit --help, -h Print this text and exit @@ -94,6 +94,32 @@ Then open with a broswer, you will get a bash shell with - You can even run a none shell command like vim, try: `ttyd vim`, the web broswer will show you a vim editor. - Sharing single process with multiple clients: `ttyd tmux new -A -s ttyd vim`, run `tmux new -A -s ttyd` to connect to the tmux session from terminal. +## SSL how-to + +Generate SSL CA and self signed server/client certificates: + +```bash +# CA +openssl genrsa -out ca.key 4096 +openssl req -new -x509 -days 365 -key ca.key -out ca.crt +# server certificate +openssl req -newkey rsa:2048 -nodes -keyout server.key -out server.csr +openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt +# client certificate (the p12/pem format may be useful for some clients) +openssl req -newkey rsa:2048 -nodes -keyout client.key -out client.csr +openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 02 -out client.crt +openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12 +openssl pkcs12 -in client.p12 -out client.pem -clcerts +``` + +Then start ttyd: + +```bash +ttyd --ssl --ssl-cert ca.crt --ssl-key ca.key --ssl-ca ca.crt bash +``` + +If you don't want to enable client certificate verification, remove the `--ssl-ca` option. + ## Docker and ttyd Docker containers are jailed environments which are more secure, this is useful for protecting the host system, you may use ttyd with docker like this: diff --git a/src/http.c b/src/http.c index 52e207f..2502651 100644 --- a/src/http.c +++ b/src/http.c @@ -127,6 +127,15 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, voi if (lws_write_http(wsi, index_html, index_html_len) < 0) return 1; goto try_to_reuse; + case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: + if (!len || (SSL_get_verify_result((SSL*)in) != X509_V_OK)) { + int err = X509_STORE_CTX_get_error((X509_STORE_CTX*)user); + int depth = X509_STORE_CTX_get_error_depth((X509_STORE_CTX*)user); + const char* msg = X509_verify_cert_error_string(err); + lwsl_err("client certificate verification error: %s (%d), depth: %d\n", msg, err, depth); + return 1; + } + break; default: break; } diff --git a/src/protocol.c b/src/protocol.c index 776aba1..d3ef925 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -133,7 +133,7 @@ thread_run_command(void *args) { pid_t pid = forkpty(&pty, NULL, NULL, NULL); switch (pid) { - case -1: /* */ + case -1: /* error */ lwsl_err("forkpty\n"); break; case 0: /* child */ diff --git a/src/server.c b/src/server.c index 44edae5..d40baa4 100644 --- a/src/server.c +++ b/src/server.c @@ -61,10 +61,10 @@ void print_help() { " --client-option, -t Send option to client (format: key=value), repeat to add more options\n" " --check-origin, -O Do not allow websocket connection from different origin\n" " --once, -o Accept only one client and exit on disconnection\n" - " --ssl, -S Enable ssl\n" - " --ssl-cert, -C Ssl certificate file path\n" - " --ssl-key, -K Ssl key file path\n" - " --ssl-ca, -A Ssl ca file path\n" + " --ssl, -S Enable SSL\n" + " --ssl-cert, -C SSL certificate file path\n" + " --ssl-key, -K SSL key file path\n" + " --ssl-ca, -A SSL CA file path for client certificate verification\n" " --debug, -d Set log level (0-9, default: 7)\n" " --version, -v Print the version and exit\n" " --help, -h Print this text and exit\n", @@ -332,6 +332,8 @@ main(int argc, char **argv) { "!DHE-RSA-AES256-SHA256:" "!AES256-GCM-SHA384:" "!AES256-SHA256"; + if (strlen(info.ssl_ca_filepath) > 0) + info.options |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT; #if LWS_LIBRARY_VERSION_MAJOR == 2 info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS; #endif -- 2.43.4