]> git.ipfire.org Git - thirdparty/knot-resolver.git/blob
370668907056f769e2d09bf7bd2e768249049f8f
[thirdparty/knot-resolver.git] /
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 * Licensed under the terms of GPLv3 (or any later version) at your choice.
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 #define _GNU_SOURCE /* for RTLD_NEXT */
31 #include <dlfcn.h>
32 #ifndef NO_OPENSSL_102_SUPPORT
33 # include <openssl/ssl.h>
34 #endif /* ! NO_OPENSSL_102_SUPPORT */
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40
41 #ifndef OPENSSL_SONAME
42 /* fallback library if OpenSSL is not already loaded. Other values to try:
43 * libssl.so.0.9.8 libssl.so.1.0.0 libssl.so.1.1 */
44 # define OPENSSL_SONAME "libssl.so"
45 #endif
46
47 #define FIRSTLINE "# SSL key logfile generated by sslkeylog.c\n"
48 #define FIRSTLINE_LEN (sizeof(FIRSTLINE) - 1)
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 static inline void put_hex(char *buffer, int pos, char c)
71 {
72 unsigned char c1 = ((unsigned char) c) >> 4;
73 unsigned char c2 = c & 0xF;
74 buffer[pos] = c1 < 10 ? '0' + c1 : 'A' + c1 - 10;
75 buffer[pos+1] = c2 < 10 ? '0' + c2 : 'A' + c2 - 10;
76 }
77
78 static void dump_to_fd(int fd, unsigned char *client_random,
79 unsigned char *master_key, int master_key_length)
80 {
81 int pos, i;
82 char line[PREFIX_LEN + 2 * SSL3_RANDOM_SIZE + 1 +
83 2 * SSL_MAX_MASTER_KEY_LENGTH + 1];
84
85 memcpy(line, PREFIX, PREFIX_LEN);
86 pos = PREFIX_LEN;
87 /* Client Random for SSLv3/TLS */
88 for (i = 0; i < SSL3_RANDOM_SIZE; i++) {
89 put_hex(line, pos, client_random[i]);
90 pos += 2;
91 }
92 line[pos++] = ' ';
93 /* Master Secret (size is at most SSL_MAX_MASTER_KEY_LENGTH) */
94 for (i = 0; i < master_key_length; i++) {
95 put_hex(line, pos, master_key[i]);
96 pos += 2;
97 }
98 line[pos++] = '\n';
99 /* Write at once rather than using buffered I/O. Perhaps there is concurrent
100 * write access so do not write hex values one by one. */
101 write(fd, line, pos);
102 }
103 #endif /* ! NO_OPENSSL_110_SUPPORT */
104
105 static void init_keylog_file(void)
106 {
107 if (keylog_file_fd >= 0)
108 return;
109
110 const char *filename = getenv("SSLKEYLOGFILE");
111 if (filename) {
112 keylog_file_fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0644);
113 if (keylog_file_fd >= 0 && lseek(keylog_file_fd, 0, SEEK_END) == 0) {
114 /* file is opened successfully and there is no data (pos == 0) */
115 write(keylog_file_fd, FIRSTLINE, FIRSTLINE_LEN);
116 }
117 }
118 }
119
120 static inline void *try_lookup_symbol(const char *sym, int optional)
121 {
122 void *func = dlsym(RTLD_NEXT, sym);
123 if (!func && optional && dlsym(RTLD_NEXT, "SSL_new")) {
124 /* Symbol not found, but an old OpenSSL version was actually loaded. */
125 return NULL;
126 }
127 /* Symbol not found, OpenSSL is not loaded (linked) so try to load it
128 * manually. This is error-prone as it depends on a fixed library name.
129 * Perhaps it should be an env name? */
130 if (!func) {
131 void *handle = dlopen(OPENSSL_SONAME, RTLD_LAZY);
132 if (!handle) {
133 fprintf(stderr, "Lookup error for %s: %s\n", sym, dlerror());
134 abort();
135 }
136 func = dlsym(handle, sym);
137 if (!func && !optional) {
138 fprintf(stderr, "Cannot lookup %s\n", sym);
139 abort();
140 }
141 dlclose(handle);
142 }
143 return func;
144 }
145
146 static inline void *lookup_symbol(const char *sym)
147 {
148 return try_lookup_symbol(sym, 0);
149 }
150
151 #ifndef NO_OPENSSL_110_SUPPORT
152 typedef struct ssl_tap_state {
153 int master_key_length;
154 unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
155
156 } ssl_tap_state_t;
157
158 static inline SSL_SESSION *ssl_get_session(const SSL *ssl)
159 {
160 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
161 static SSL_SESSION *(*func)();
162 if (!func) {
163 func = lookup_symbol("SSL_get_session");
164 }
165 return func(ssl);
166 #else
167 return ssl->session;
168 #endif
169 }
170
171 static void copy_master_secret(const SSL_SESSION *session,
172 unsigned char *master_key_out, int *keylen_out)
173 {
174 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
175 static size_t (*func)();
176 if (!func) {
177 func = lookup_symbol("SSL_SESSION_get_master_key");
178 }
179 *keylen_out = func(session, master_key_out, SSL_MAX_MASTER_KEY_LENGTH);
180 #else
181 if (session->master_key_length > 0) {
182 *keylen_out = session->master_key_length;
183 memcpy(master_key_out, session->master_key,
184 session->master_key_length);
185 }
186 #endif
187 }
188
189 static void copy_client_random(const SSL *ssl, unsigned char *client_random)
190 {
191 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
192 static size_t (*func)();
193 if (!func) {
194 func = lookup_symbol("SSL_get_client_random");
195 }
196 /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that
197 * we have a valid SSL context if we have a non-NULL session. */
198 func(ssl, client_random, SSL3_RANDOM_SIZE);
199 #else
200 if (ssl->s3) {
201 memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE);
202 }
203 #endif
204 }
205
206 /* non-NULL if the new OpenSSL 1.1.1 keylog API is supported. */
207 static int supports_keylog_api(void)
208 {
209 static int supported = -1;
210 if (supported == -1) {
211 supported = try_lookup_symbol("SSL_CTX_set_keylog_callback", 1) != NULL;
212 }
213 return supported;
214 }
215
216 /* Copies SSL state for later comparison in tap_ssl_key. */
217 static void ssl_tap_state_init(ssl_tap_state_t *state, const SSL *ssl)
218 {
219 if (supports_keylog_api()) {
220 /* Favor using the callbacks API to extract secrets. */
221 return;
222 }
223
224 const SSL_SESSION *session = ssl_get_session(ssl);
225
226 memset(state, 0, sizeof(ssl_tap_state_t));
227 if (session) {
228 copy_master_secret(session, state->master_key, &state->master_key_length);
229 }
230 }
231
232 #define SSL_TAP_STATE(state, ssl) \
233 ssl_tap_state_t state; \
234 ssl_tap_state_init(&state, ssl)
235
236 static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state)
237 {
238 if (supports_keylog_api()) {
239 /* Favor using the callbacks API to extract secrets. */
240 return;
241 }
242
243 const SSL_SESSION *session = ssl_get_session(ssl);
244 unsigned char client_random[SSL3_RANDOM_SIZE];
245 unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
246 int master_key_length = 0;
247
248 if (session) {
249 copy_master_secret(session, master_key, &master_key_length);
250 /* Assume we have a client random if the master key is set. */
251 if (master_key_length > 0) {
252 copy_client_random(ssl, client_random);
253 }
254 }
255
256 /* Write the logfile when the master key is available for SSLv3/TLSv1. */
257 if (master_key_length > 0) {
258 /* Skip writing keys if it did not change. */
259 if (state->master_key_length == master_key_length &&
260 memcmp(state->master_key, master_key, master_key_length) == 0) {
261 return;
262 }
263
264 init_keylog_file();
265 if (keylog_file_fd >= 0) {
266 dump_to_fd(keylog_file_fd, client_random, master_key,
267 master_key_length);
268 }
269 }
270 }
271
272 int SSL_connect(SSL *ssl)
273 {
274 static int (*func)();
275 if (!func) {
276 func = lookup_symbol(__func__);
277 }
278 SSL_TAP_STATE(state, ssl);
279 int ret = func(ssl);
280 tap_ssl_key(ssl, &state);
281 return ret;
282 }
283
284 int SSL_do_handshake(SSL *ssl)
285 {
286 static int (*func)();
287 if (!func) {
288 func = lookup_symbol(__func__);
289 }
290 SSL_TAP_STATE(state, ssl);
291 int ret = func(ssl);
292 tap_ssl_key(ssl, &state);
293 return ret;
294 }
295
296 int SSL_accept(SSL *ssl)
297 {
298 static int (*func)();
299 if (!func) {
300 func = lookup_symbol(__func__);
301 }
302 SSL_TAP_STATE(state, ssl);
303 int ret = func(ssl);
304 tap_ssl_key(ssl, &state);
305 return ret;
306 }
307
308 int SSL_read(SSL *ssl, void *buf, int num)
309 {
310 static int (*func)();
311 if (!func) {
312 func = lookup_symbol(__func__);
313 }
314 SSL_TAP_STATE(state, ssl);
315 int ret = func(ssl, buf, num);
316 tap_ssl_key(ssl, &state);
317 return ret;
318 }
319
320 int SSL_write(SSL *ssl, const void *buf, int num)
321 {
322 static int (*func)();
323 if (!func) {
324 func = lookup_symbol(__func__);
325 }
326 SSL_TAP_STATE(state, ssl);
327 int ret = func(ssl, buf, num);
328 tap_ssl_key(ssl, &state);
329 return ret;
330 }
331 #endif /* ! NO_OPENSSL_110_SUPPORT */
332
333 /* Key extraction via the new OpenSSL 1.1.1 API. */
334 static void keylog_callback(const SSL *ssl, const char *line)
335 {
336 init_keylog_file();
337 if (keylog_file_fd >= 0) {
338 write(keylog_file_fd, line, strlen(line));
339 write(keylog_file_fd, "\n", 1);
340 }
341 }
342
343 SSL *SSL_new(SSL_CTX *ctx)
344 {
345 static SSL *(*func)();
346 static void (*set_keylog_cb)();
347 if (!func) {
348 func = lookup_symbol(__func__);
349 #ifdef NO_OPENSSL_110_SUPPORT
350 /* The new API MUST be available since OpenSSL 1.1.1. */
351 set_keylog_cb = lookup_symbol("SSL_CTX_set_keylog_callback");
352 #else /* ! NO_OPENSSL_110_SUPPORT */
353 /* May be NULL if used with an older OpenSSL runtime library. */
354 set_keylog_cb = try_lookup_symbol("SSL_CTX_set_keylog_callback", 1);
355 #endif /* ! NO_OPENSSL_110_SUPPORT */
356 }
357 if (set_keylog_cb) {
358 /* Override any previous key log callback. */
359 set_keylog_cb(ctx, keylog_callback);
360 }
361 return func(ctx);
362 }