1 /*
2  * Dumps master keys for OpenSSL clients to file. The format is documented at
3  * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
4  * Supports TLS 1.3 when used with OpenSSL 1.1.1.
5  *
6  * Copyright (C) 2014 Peter Wu <peter@lekensteyn.nl>
7  * SPDX-License-Identifier: GPL-3.0-or-later
8  *
9  * Usage:
10  *  cc sslkeylog.c -shared -o libsslkeylog.so -fPIC -ldl
11  *  SSLKEYLOGFILE=premaster.txt LD_PRELOAD=./libsslkeylog.so openssl ...
12  */
13 
14 /*
15  * A single libsslkeylog.so supports multiple OpenSSL runtime versions. If you
16  * would like to build this library without OpenSSL development headers and do
17  * not require support for older OpenSSL versions, then disable it by defining
18  * the NO_OPENSSL_102_SUPPORT or NO_OPENSSL_110_SUPPORT macros.
19  */
20 /* Define to drop OpenSSL <= 1.0.2 support and require OpenSSL >= 1.1.0. */
21 //#define NO_OPENSSL_102_SUPPORT
22 /* Define to drop OpenSSL <= 1.1.0 support and require OpenSSL >= 1.1.1. */
23 //#define NO_OPENSSL_110_SUPPORT
24 
25 /* No OpenSSL 1.1.0 support implies no OpenSSL 1.0.2 support. */
26 #ifdef NO_OPENSSL_110_SUPPORT
27 #   define NO_OPENSSL_102_SUPPORT
28 #endif
29 
30 #ifndef _GNU_SOURCE
31 #   define _GNU_SOURCE /* for RTLD_NEXT */
32 #endif
33 
34 #include <dlfcn.h>
35 #ifndef NO_OPENSSL_102_SUPPORT
36 #   include <openssl/ssl.h>
37 #endif /* ! NO_OPENSSL_102_SUPPORT */
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 
44 #ifndef OPENSSL_SONAME
45 /* fallback library if OpenSSL is not already loaded. Other values to try:
46  * libssl.so.0.9.8 libssl.so.1.0.0 libssl.so.1.1 */
47 #   define OPENSSL_SONAME   "libssl.so"
48 #endif
49 
50 /* When building for OpenSSL 1.1.0 or newer, no headers are required. */
51 #ifdef NO_OPENSSL_102_SUPPORT
52 typedef struct ssl_st SSL;
53 typedef struct ssl_ctx_st SSL_CTX;
54 /* Extra definitions for OpenSSL 1.1.0 support when headers are unavailable. */
55 #   ifndef NO_OPENSSL_110_SUPPORT
56 typedef struct ssl_session_st SSL_SESSION;
57 #       define SSL3_RANDOM_SIZE 32
58 #       define SSL_MAX_MASTER_KEY_LENGTH 48
59 #       define OPENSSL_VERSION_NUMBER 0x10100000L
60 #   endif /* ! NO_OPENSSL_110_SUPPORT */
61 #endif /* ! NO_OPENSSL_102_SUPPORT */
62 
63 static int keylog_file_fd = -1;
64 
65 /* Legacy routines for dumping TLS <= 1.2 secrets on older OpenSSL versions. */
66 #ifndef NO_OPENSSL_110_SUPPORT
67 #define PREFIX      "CLIENT_RANDOM "
68 #define PREFIX_LEN  (sizeof(PREFIX) - 1)
69 
70 #pragma GCC diagnostic ignored "-Wpedantic"
71 #pragma GCC diagnostic ignored "-Wunused-result"
72 
put_hex(char * buffer,int pos,char c)73 static inline void put_hex(char *buffer, int pos, char c)
74 {
75     unsigned char c1 = ((unsigned char) c) >> 4;
76     unsigned char c2 = c & 0xF;
77     buffer[pos] = c1 < 10 ? '0' + c1 : 'A' + c1 - 10;
78     buffer[pos+1] = c2 < 10 ? '0' + c2 : 'A' + c2 - 10;
79 }
80 
dump_to_fd(int fd,unsigned char * client_random,unsigned char * master_key,int master_key_length)81 static void dump_to_fd(int fd, unsigned char *client_random,
82         unsigned char *master_key, int master_key_length)
83 {
84     int pos, i;
85     char line[PREFIX_LEN + 2 * SSL3_RANDOM_SIZE + 1 +
86               2 * SSL_MAX_MASTER_KEY_LENGTH + 1];
87 
88     memcpy(line, PREFIX, PREFIX_LEN);
89     pos = PREFIX_LEN;
90     /* Client Random for SSLv3/TLS */
91     for (i = 0; i < SSL3_RANDOM_SIZE; i++) {
92         put_hex(line, pos, client_random[i]);
93         pos += 2;
94     }
95     line[pos++] = ' ';
96     /* Master Secret (size is at most SSL_MAX_MASTER_KEY_LENGTH) */
97     for (i = 0; i < master_key_length; i++) {
98         put_hex(line, pos, master_key[i]);
99         pos += 2;
100     }
101     line[pos++] = '\n';
102     /* Write at once rather than using buffered I/O. Perhaps there is concurrent
103      * write access so do not write hex values one by one. */
104     write(fd, line, pos);
105 }
106 #endif /* ! NO_OPENSSL_110_SUPPORT */
107 
init_keylog_file(void)108 static void init_keylog_file(void)
109 {
110     if (keylog_file_fd >= 0)
111         return;
112 
113     const char *filename = getenv("OPENSSLKEYLOGFILE");
114     if (filename) {
115 	/* ctime output is max 26 bytes, POSIX 1003.1-2017 */
116 	keylog_file_fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
117         if (keylog_file_fd >= 0) {
118             time_t timenow = time(NULL);
119             char txtnow[30] = { '#', ' ', 0 };
120 	    ctime_r(&timenow, txtnow + 2);
121             /* file is opened successfully and there is no data (pos == 0) */
122             write(keylog_file_fd, txtnow, strlen(txtnow));
123         }
124     }
125 }
126 
try_lookup_symbol(const char * sym,int optional)127 static inline void *try_lookup_symbol(const char *sym, int optional)
128 {
129     void *func = dlsym(RTLD_NEXT, sym);
130     if (!func && optional && dlsym(RTLD_NEXT, "SSL_new")) {
131         /* Symbol not found, but an old OpenSSL version was actually loaded. */
132         return NULL;
133     }
134     /* Symbol not found, OpenSSL is not loaded (linked) so try to load it
135      * manually. This is error-prone as it depends on a fixed library name.
136      * Perhaps it should be an env name? */
137     if (!func) {
138         void *handle = dlopen(OPENSSL_SONAME, RTLD_LAZY);
139         if (!handle) {
140             fprintf(stderr, "Lookup error for %s: %s\n", sym, dlerror());
141             abort();
142         }
143         func = dlsym(handle, sym);
144         if (!func && !optional) {
145             fprintf(stderr, "Cannot lookup %s\n", sym);
146             abort();
147         }
148         dlclose(handle);
149     }
150     return func;
151 }
152 
lookup_symbol(const char * sym)153 static inline void *lookup_symbol(const char *sym)
154 {
155     return try_lookup_symbol(sym, 0);
156 }
157 
158 #ifndef NO_OPENSSL_110_SUPPORT
159 typedef struct ssl_tap_state {
160     int master_key_length;
161     unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
162 
163 } ssl_tap_state_t;
164 
ssl_get_session(const SSL * ssl)165 static inline SSL_SESSION *ssl_get_session(const SSL *ssl)
166 {
167 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
168     static SSL_SESSION *(*func)();
169     if (!func) {
170         func = lookup_symbol("SSL_get_session");
171     }
172     return func(ssl);
173 #else
174     return ssl->session;
175 #endif
176 }
177 
copy_master_secret(const SSL_SESSION * session,unsigned char * master_key_out,int * keylen_out)178 static void copy_master_secret(const SSL_SESSION *session,
179         unsigned char *master_key_out, int *keylen_out)
180 {
181 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
182     static size_t (*func)();
183     if (!func) {
184         func = lookup_symbol("SSL_SESSION_get_master_key");
185     }
186     *keylen_out = func(session, master_key_out, SSL_MAX_MASTER_KEY_LENGTH);
187 #else
188     if (session->master_key_length > 0) {
189         *keylen_out = session->master_key_length;
190         memcpy(master_key_out, session->master_key,
191                 session->master_key_length);
192     }
193 #endif
194 }
195 
copy_client_random(const SSL * ssl,unsigned char * client_random)196 static void copy_client_random(const SSL *ssl, unsigned char *client_random)
197 {
198 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
199     static size_t (*func)();
200     if (!func) {
201         func = lookup_symbol("SSL_get_client_random");
202     }
203     /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that
204      * we have a valid SSL context if we have a non-NULL session. */
205     func(ssl, client_random, SSL3_RANDOM_SIZE);
206 #else
207     if (ssl->s3) {
208         memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE);
209     }
210 #endif
211 }
212 
213 /* non-NULL if the new OpenSSL 1.1.1 keylog API is supported. */
supports_keylog_api(void)214 static int supports_keylog_api(void)
215 {
216     static int supported = -1;
217     if (supported == -1) {
218         supported = try_lookup_symbol("SSL_CTX_set_keylog_callback", 1) != NULL;
219     }
220     return supported;
221 }
222 
223 /* Copies SSL state for later comparison in tap_ssl_key. */
ssl_tap_state_init(ssl_tap_state_t * state,const SSL * ssl)224 static void ssl_tap_state_init(ssl_tap_state_t *state, const SSL *ssl)
225 {
226     if (supports_keylog_api()) {
227         /* Favor using the callbacks API to extract secrets. */
228         return;
229     }
230 
231     const SSL_SESSION *session = ssl_get_session(ssl);
232 
233     memset(state, 0, sizeof(ssl_tap_state_t));
234     if (session) {
235         copy_master_secret(session, state->master_key, &state->master_key_length);
236     }
237 }
238 
239 #define SSL_TAP_STATE(state, ssl) \
240     ssl_tap_state_t state; \
241     ssl_tap_state_init(&state, ssl)
242 
tap_ssl_key(const SSL * ssl,ssl_tap_state_t * state)243 static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state)
244 {
245     if (supports_keylog_api()) {
246         /* Favor using the callbacks API to extract secrets. */
247         return;
248     }
249 
250     const SSL_SESSION *session = ssl_get_session(ssl);
251     unsigned char client_random[SSL3_RANDOM_SIZE];
252     unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
253     int master_key_length = 0;
254 
255     if (session) {
256         copy_master_secret(session, master_key, &master_key_length);
257         /* Assume we have a client random if the master key is set. */
258         if (master_key_length > 0) {
259             copy_client_random(ssl, client_random);
260         }
261     }
262 
263     /* Write the logfile when the master key is available for SSLv3/TLSv1. */
264     if (master_key_length > 0) {
265         /* Skip writing keys if it did not change. */
266         if (state->master_key_length == master_key_length &&
267             memcmp(state->master_key, master_key, master_key_length) == 0) {
268             return;
269         }
270 
271         init_keylog_file();
272         if (keylog_file_fd >= 0) {
273             dump_to_fd(keylog_file_fd, client_random, master_key,
274                     master_key_length);
275         }
276     }
277 }
278 
SSL_connect(SSL * ssl)279 int SSL_connect(SSL *ssl)
280 {
281     static int (*func)();
282     if (!func) {
283         func = lookup_symbol(__func__);
284     }
285     SSL_TAP_STATE(state, ssl);
286     int ret = func(ssl);
287     tap_ssl_key(ssl, &state);
288     return ret;
289 }
290 
SSL_do_handshake(SSL * ssl)291 int SSL_do_handshake(SSL *ssl)
292 {
293     static int (*func)();
294     if (!func) {
295         func = lookup_symbol(__func__);
296     }
297     SSL_TAP_STATE(state, ssl);
298     int ret = func(ssl);
299     tap_ssl_key(ssl, &state);
300     return ret;
301 }
302 
SSL_accept(SSL * ssl)303 int SSL_accept(SSL *ssl)
304 {
305     static int (*func)();
306     if (!func) {
307         func = lookup_symbol(__func__);
308     }
309     SSL_TAP_STATE(state, ssl);
310     int ret = func(ssl);
311     tap_ssl_key(ssl, &state);
312     return ret;
313 }
314 
SSL_read(SSL * ssl,void * buf,int num)315 int SSL_read(SSL *ssl, void *buf, int num)
316 {
317     static int (*func)();
318     if (!func) {
319         func = lookup_symbol(__func__);
320     }
321     SSL_TAP_STATE(state, ssl);
322     int ret = func(ssl, buf, num);
323     tap_ssl_key(ssl, &state);
324     return ret;
325 }
326 
SSL_write(SSL * ssl,const void * buf,int num)327 int SSL_write(SSL *ssl, const void *buf, int num)
328 {
329     static int (*func)();
330     if (!func) {
331         func = lookup_symbol(__func__);
332     }
333     SSL_TAP_STATE(state, ssl);
334     int ret = func(ssl, buf, num);
335     tap_ssl_key(ssl, &state);
336     return ret;
337 }
338 #endif /* ! NO_OPENSSL_110_SUPPORT */
339 
340 /* Key extraction via the new OpenSSL 1.1.1 API. */
keylog_callback(const SSL * ssl,const char * line)341 static void keylog_callback(const SSL *ssl, const char *line)
342 {
343     init_keylog_file();
344     if (keylog_file_fd >= 0) {
345         write(keylog_file_fd, line, strlen(line));
346         write(keylog_file_fd, "\n", 1);
347     }
348 }
349 
SSL_new(SSL_CTX * ctx)350 SSL *SSL_new(SSL_CTX *ctx)
351 {
352     static SSL *(*func)();
353     static void (*set_keylog_cb)();
354     if (!func) {
355         func = lookup_symbol(__func__);
356 #ifdef NO_OPENSSL_110_SUPPORT
357         /* The new API MUST be available since OpenSSL 1.1.1. */
358         set_keylog_cb = lookup_symbol("SSL_CTX_set_keylog_callback");
359 #else  /* ! NO_OPENSSL_110_SUPPORT */
360         /* May be NULL if used with an older OpenSSL runtime library. */
361         set_keylog_cb = try_lookup_symbol("SSL_CTX_set_keylog_callback", 1);
362 #endif /* ! NO_OPENSSL_110_SUPPORT */
363     }
364     if (set_keylog_cb) {
365         /* Override any previous key log callback. */
366         set_keylog_cb(ctx, keylog_callback);
367     }
368     return func(ctx);
369 }
370