diff --git a/README.markdown b/README.markdown index 3936db1..fdb2760 100644 --- a/README.markdown +++ b/README.markdown @@ -48,6 +48,8 @@ Table of Contents * [ngx-orig-resp-body-len](#ngx-orig-resp-body-len) * [zlib-deflate-chunk-size](#zlib-deflate-chunk-size) * [lj-str-tab](#lj-str-tab) + * [ngx-ssl-session-ticket-keys](#ngx-ssl-session-ticket-keys) + * [ngx-ssl-session-ticket-resumption-stats](#ngx-ssl-session-ticket-resumption-stats) * [Installation](#installation) * [Author](#author) * [Copyright and License](#copyright-and-license) @@ -1453,7 +1455,67 @@ value |-------------------------------------------------- count lj-str-tab ---------- -Analayzing the structure and various statistics of the global Lua string hash table in the LuaJIT v2.1 VM. +Analyzing the structure and various statistics of the global Lua string hash table in the LuaJIT v2.1 VM. + +[Back to TOC](#table-of-contents) + +ngx-ssl-session-ticket-keys +---------- + +Dumping ssl session ticket keys of a nginx worker. It will exit on the first +time it captures the ticket keys. It can be utilized as a cron job to monitor if +session ticket rotation actually happends. + +```bash +# making the ./stap++ tool visible in PATH: +$ export PATH=$PWD:$PATH + +# assuming one nginx worker process has the pid 3781. +$ ./samples/ngx-ssl-session-ticket-keys.sxx -x 3781 +Tracing process 3781 (/etc/nginx/sbin/nginx). +Exit on first capture. Or hit Ctrl-C to end. +Number of keys: 3 +encryption key: + name: 5589398e87a104dd30691fbc3c8446c6 +decryption key #1: + name: f14c1d6611ad4802eccf6332f3b356f5 +decryption key #2: + name: b9cb4fb269a4148cc7c19c71d9e8554d +``` + +[Back to TOC](#table-of-contents) + +ngx-ssl-session-ticket-resumption-stats +---------- + +Analyzing the statistics of nginx SSL/TLS session ticket resumption. +It counts the total number of session ticket encryption/decryption events +Then it calculates the ratio of session ticket resumption attempts versus +session ticket eligible connections and the ratio of successful session ticket +resumption versus total number of session ticket resumption attemtps. Finally, +it calculates the session ticket resumption rate as the product of the above +two ratio. + +Here is an example on monitoring session ticket resumption statistics +on a local nginx instance for 30 seconds. + +```bash +# making the ./stap++ tool visible in PATH: +$ export PATH=$PWD:$PATH + +# assuming one nginx worker process has the pid 3781. +$ ./samples/ngx-ssl-session-ticket-resumption-stats.sxx -x 3781 --arg time=30 +Tracing process 3781 (/etc/nginx/sbin/nginx). +Pleasese wait for 30 seconds... +Stop tracing NGX OPENSSL ticket key callback +Total sessions: 11 +Total session tickets: 10 +Total resumed session ticket: 10 +Total re-encrypted session ticket: 0 +Session ticket resumption attempts ratio: 90% +Session ticket resumption success ratio: 100% +Total session ticket resumption rate: 90% +``` [Back to TOC](#table-of-contents) diff --git a/samples/ngx-ssl-session-ticket-keys.sxx b/samples/ngx-ssl-session-ticket-keys.sxx new file mode 100755 index 0000000..9e029f4 --- /dev/null +++ b/samples/ngx-ssl-session-ticket-keys.sxx @@ -0,0 +1,57 @@ +#!/usr/bin/env stap++ + +# Capture ssl session tickets. + +@use nginx.array +@use openssl + +probe begin { + printf("Tracing process %d ($^exec_path).\nExit on first capture. Or hit Ctrl-C to end.\n", target()) +} + +// print 16-byte key name +function print_key_name(name) { + printf("\tname: "); + $*n := @cast(name, "unsigned char", "$^exec_path") + for (i=0; i<16; i++) { + printf("%02x", $*n[i]) + } + printf("\n") +} + +// print session ticket content +function print_session_ticket_key(key) { + $*k := @cast(key, "ngx_ssl_session_ticket_key_t", "$^exec_path") + print_key_name($*k->name) + // could be extended to print out other cipher states +} + +probe @pfunc(ngx_ssl_session_ticket_key_callback).return { + keys_index = @var("ngx_ssl_session_ticket_keys_index@src/event/ngx_event_openssl.c") + num = get_ssl_ex_data_len($ssl_conn->ctx) + if (keys_index > num) { + printf("Error: ticket key list is not supported") + + } else { + keys = get_ssl_ex_data_item($ssl_conn->ctx, keys_index) + keys_len = get_ngx_array_len(keys) + if (keys_len <= 0) { + printf("Error: empty key list") + + } else { + key_ptr = get_ngx_array_elts(keys) + printf("Number of keys: %d\n", keys_len) + for (i=0; i 0) resumed++; + if ($return > 1) reencrypted++; + } +} + +%( "$^arg_time" != "" %? +probe timer.s($^arg_time) { + exit() +} +%) + +probe end { + printf("Stop tracing NGX OPENSSL ticket key callback\n"); + printf("Total sessions: %d\n", total); + printf("Total session tickets: %d\n", tickets); + printf("Total resumed session ticket: %d\n", resumed); + printf("Total re-encrypted session ticket: %d\n", reencrypted); + + if (total > 0) { + ratio1 = (tickets * 100) / total; + + } else { + ratio1 = 0; + } + + if (tickets > 0) { + ratio2 = (resumed * 100) / tickets; + + } else { + ratio2 = 0; + } + printf("Session ticket resumption attempts ratio: %d%%\n", ratio1) + printf("Session ticket resumption success ratio: %d%%\n", ratio2) + printf("Total session ticket resumption rate: %d%%\n", + ratio1 * ratio2 / 100) + exit(); +} diff --git a/tapset/nginx/array.sxx b/tapset/nginx/array.sxx new file mode 100644 index 0000000..0d4f448 --- /dev/null +++ b/tapset/nginx/array.sxx @@ -0,0 +1,12 @@ +// module nginx.array + +function get_ngx_array_len(ngx_arr) { + $*arr := @cast(ngx_arr, "ngx_array_t", "$^exec_path") + return $*arr->nelts + +} + +function get_ngx_array_elts(ngx_arr) { + $*arr := @cast(ngx_arr, "ngx_array_t", "$^exec_path") + return $*arr->elts +} diff --git a/tapset/openssl.sxx b/tapset/openssl.sxx new file mode 100644 index 0000000..0d3bb48 --- /dev/null +++ b/tapset/openssl.sxx @@ -0,0 +1,21 @@ +// module openssl + +// extract ex_data pointer from openssl SSL_CTX +function get_ssl_ex_data(ssl_ctx) { + $*ctx := @cast(ssl_ctx, "SSL_CTX", "$^exec_path") + return &$*ctx->ex_data +} + +// extract number of items in SSL_CTX ex_data +function get_ssl_ex_data_len(ssl_ctx) { + ex_data = get_ssl_ex_data(ssl_ctx) + $*data := @cast(ex_data, "CRYPTO_EX_DATA", "$^exec_path") + return $*data->sk->stack->num +} + +// extract the item specified by idx in SSL_CTX ex_data +function get_ssl_ex_data_item(ssl_ctx, idx) { + ex_data = get_ssl_ex_data(ssl_ctx) + $*data := @cast(ex_data, "CRYPTO_EX_DATA", "$^exec_path") + return $*data->sk->stack->data[idx] +}