Module: SSLkeylog::OpenSSL
- Defined in:
- ext/openssl/openssl.c,
ext/openssl/openssl.c
Overview
Generate NSS Key Log entries from Ruby OpenSSL objects
The NSS Key Log format contains two pieces of information that can be used to decrypt SSL session data:
A string of 32 random bytes sent by the client during the "Client Hello" phase of the SSL handshake.
A string of 48 bytes generated during the handshake that is the "pre-master key" required to decrypt the data.
The Ruby OpenSSL library exposes the pre-master key through the to_text
method of OpenSSL::SSL::Session objects. Unfortunately, there is no way
to access the client random data at the Ruby level. However, many Ruby
objects are simple wrappers for C data structures and the OpenSSL SSL
struct does contains all the data we need --- including the client random
data. The Ruby object which wraps struct SSL is
OpenSSL::SSL::SSLSocket. This to_keylog method provided is a simple C
extension which un-wraps SSLSocket objects at the C level and reads the
data required form a NSS Key Log entry.
Constant Summary collapse
- OPENSSL_VERSION =
The version string of the OpenSSL headers used to build this library.
rb_str_new2(OPENSSL_VERSION_TEXT)
- OPENSSL_VERSION_NUMBER =
The numeric version of the OpenSSL headers used to build this library.
INT2NUM(OPENSSL_VERSION_NUMBER)
Class Method Summary collapse
-
.to_keylog(socket) ⇒ String?
Capture SSL session keys in NSS Key Log Format.
Class Method Details
.to_keylog(socket) ⇒ String?
Capture SSL session keys in NSS Key Log Format
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'ext/openssl/openssl.c', line 32 static VALUE to_keylog(VALUE mod, VALUE socket) { SSL *ssl; // 14 byte header string // + 64 byte hex encoded client random // + 1 space // + 96 byte hex encoded master secret // + newline. size_t buf_len = 14 + 64 + 1 + 96 + 1; char buf[buf_len]; unsigned int i; // PRIsVALUE is a special format string that causes functions like rb_raise // to format data of type VALUE by calling `.to_s` on the Ruby object. if (!rb_obj_is_instance_of(socket, cSSLSocket)) { rb_raise(rb_eTypeError, "wrong argument (%"PRIsVALUE")! (Expected instance of %"PRIsVALUE")", rb_obj_class(socket), cSSLSocket); } // NOTE: Should be able to use Data_Get_Struct here, but for some reason the // SSLSocket instance passed to this function as `socket` fails the // type check. // // So, we live dangerously and go directly for the data pointer. ssl = (SSL*)DATA_PTR(socket); // Check to see if the SSL data structure has been populated. // // NOTE: If the `s3` component is missing then SSLv2 is in use and we bail // out. Such a thing is a bit crazy these days, but we could handle it in a // more meaningful way by falling back to the old NSS Key Log format: // // RSA Session-ID:<16 byte session id> Master-Key:<48 byte master key> if ( !(ssl) || !(ssl->session) || !(ssl->s3) ){ return Qnil; } memcpy(buf, "CLIENT_RANDOM ", 14); i = 14; hex_encode(buf + i, 32, ssl->s3->client_random); i += 64; buf[i++] = ' '; hex_encode(buf + i, 48, ssl->session->master_key); i += 96; buf[i++] = '\n'; return rb_str_new(buf, buf_len); } |