Browse code

Merge 368c13945d6d1d78541a72b29d260e50cd2fdeb4 into b8fbf5e8c199b8277053f9c15231695a16058d6e

sergey-safarov authored on 23/06/2021 07:51:19 • GitHub committed on 23/06/2021 07:51:19
Showing 7 changed files
... ...
@@ -50,6 +50,8 @@ struct cfg_group_tls default_tls_cfg = {
50 50
 	STR_NULL, /* cipher_list (default value set in fix_tls_cfg) */
51 51
 	0, /* session_cache */
52 52
 	STR_STATIC_INIT("kamailio-tls-5.x.y"), /* session_id */
53
+	0, /* session_keylog_enable */
54
+	STR_STATIC_INIT("/var/lib/kamailio/session_keylog"), /* session_keylog_filename */
53 55
 	STR_NULL, /* config_file */
54 56
 	3, /* log  (L_DBG)*/
55 57
 	3, /* debug (L_DBG) */
... ...
@@ -177,6 +179,10 @@ cfg_def_t	tls_cfg_def[] = {
177 179
 		"enables or disables the session cache" },
178 180
 	{"session_id", CFG_VAR_STR | CFG_READONLY, 0, 0, 0, 0,
179 181
 		"string used for the session id" },
182
+	{"session_keylog_enable", CFG_VAR_INT, 0, 1, 0, 0,
183
+		"enables export TLS/DTLS session keys" },
184
+	{"session_keylog_filename", CFG_VAR_STR | CFG_READONLY, 0, 0, 0, 0,
185
+		"TLS/DTLS session filename" },
180 186
 	{"config", CFG_VAR_STR, 0, 0, fix_rel_pathname, 0,
181 187
 		"tls config file name (used for the per domain options)" },
182 188
 	{"log", CFG_VAR_INT | CFG_ATOMIC, 0, 1000, 0, 0,
... ...
@@ -55,6 +55,8 @@ struct cfg_group_tls {
55 55
 	str cipher_list;
56 56
 	int session_cache;
57 57
 	str session_id;
58
+	int session_keylog_enable;   /* enable logging of TLS/DTLS session keys*/
59
+	str session_keylog_filename; /* TLS/DTLS session keys filename */
58 60
 	str config_file;
59 61
 	int log;
60 62
 	int debug;
... ...
@@ -571,6 +571,82 @@ end:
571 571
 	return 0;
572 572
 }
573 573
 
574
+static BIO *bio_keylog = NULL;
575
+
576
+/*
577
+ * Module callback function for session keys logging
578
+ */
579
+void keylog_callback(const SSL *ssl, const char *line)
580
+{
581
+	int tls_log = cfg_get(tls, tls_cfg, log);
582
+	if (bio_keylog == NULL) {
583
+		LOG(tls_log, "Keylog callback is invoked without valid file!\n");
584
+		return;
585
+	}
586
+
587
+	/*
588
+	* There might be concurrent writers to the keylog file, so we must ensure
589
+	* that the given line is written at once.
590
+	*/
591
+	BIO_printf(bio_keylog, "%s\n", line);
592
+	(void)BIO_flush(bio_keylog);
593
+}
594
+
595
+int prepare_keylog_file(str session_keylog_filename)
596
+{
597
+	char *keylog_file = NULL;
598
+	int tls_log = cfg_get(tls, tls_cfg, log);
599
+
600
+	/* Close any open files */
601
+	BIO_free_all(bio_keylog);
602
+	bio_keylog = NULL;
603
+
604
+	if (cfg_get(tls, tls_cfg, session_keylog_enable) == 0) {
605
+		/* Keylogging is disabled. */
606
+		LOG(tls_log, "Session keylog disabled\n");
607
+		return 0;
608
+	}
609
+
610
+	if (session_keylog_filename.len == 0) {
611
+		/* Keylogging filename is not specified. */
612
+		LOG(tls_log, "Session keylog filename is emptry, keylog disabled\n");
613
+		return 0;
614
+	}
615
+
616
+	keylog_file = (char *)pkg_malloc((session_keylog_filename.len * sizeof(char) + 1));
617
+	if(keylog_file == NULL) {
618
+		PKG_MEM_ERROR;
619
+		return -1;
620
+	}
621
+	memcpy(keylog_file, session_keylog_filename.s, session_keylog_filename.len);
622
+	keylog_file[session_keylog_filename.len] = 0;
623
+
624
+	/*
625
+	* Append rather than write in order to allow concurrent modification.
626
+	* Furthermore, this preserves existing keylog files which is useful when
627
+	* the tool is run multiple times.
628
+	*/
629
+	bio_keylog = BIO_new_file(keylog_file, "a");
630
+	if (bio_keylog == NULL) {
631
+		LOG(tls_log, "Error writing keylog file: %s\n", keylog_file);
632
+		return 1;
633
+	}
634
+
635
+	/* Write a header for seekable, empty files (this excludes pipes). */
636
+	if (BIO_tell(bio_keylog) == 0) {
637
+		BIO_puts(bio_keylog, "# SSL/TLS secrets log file, generated by Kamailio\n");
638
+		(void)BIO_flush(bio_keylog);
639
+	}
640
+	return 0;
641
+}
642
+
643
+void set_keylog_callback(const SSL *ssl)
644
+{
645
+	if (bio_keylog == NULL) {
646
+		return;
647
+	}
648
+	SSL_CTX_set_keylog_callback(SSL_get_SSL_CTX(ssl), keylog_callback);
649
+}
574 650
 
575 651
 /**
576 652
  * tls pre-init function
... ...
@@ -636,6 +712,7 @@ int tls_h_mod_pre_init_f(void)
636 712
 #endif
637 713
 	SSL_load_error_strings();
638 714
 	tls_mod_preinitialized=1;
715
+	prepare_keylog_file(cfg_get(tls, tls_cfg, session_keylog_filename));
639 716
 	return 0;
640 717
 }
641 718
 
... ...
@@ -865,6 +942,7 @@ int tls_check_sockets(tls_domains_cfg_t* cfg)
865 942
  */
866 943
 void tls_h_mod_destroy_f(void)
867 944
 {
945
+	str str_null = STR_NULL;
868 946
 	LM_DBG("tls module final tls destroy\n");
869 947
 	if(tls_mod_preinitialized > 0)
870 948
 		ERR_free_strings();
... ...
@@ -872,6 +950,7 @@ void tls_h_mod_destroy_f(void)
872 950
 	tls_destroy_cfg();
873 951
 	tls_destroy_locks();
874 952
 	tls_ct_wq_destroy();
953
+	prepare_keylog_file(str_null);
875 954
 #if OPENSSL_VERSION_NUMBER >= 0x010100000L && !defined(LIBRESSL_VERSION_NUMBER)
876 955
 	/* explicit execution of libssl cleanup to avoid being executed again
877 956
 	 * by atexit(), when shm is gone */
... ...
@@ -89,4 +89,6 @@ int tls_h_init_si_f(struct socket_info *si);
89 89
  */
90 90
 int tls_check_sockets(tls_domains_cfg_t* cfg);
91 91
 
92
+void set_keylog_callback(const SSL *ssl);
93
+
92 94
 #endif /* _TLS_INIT_H */
... ...
@@ -233,6 +233,8 @@ static param_export_t params[] = {
233 233
 	{"tls_debug",           PARAM_INT,    &default_tls_cfg.debug        },
234 234
 	{"session_cache",       PARAM_INT,    &default_tls_cfg.session_cache},
235 235
 	{"session_id",          PARAM_STR,    &default_tls_cfg.session_id   },
236
+	{"session_keylog_enable", PARAM_INT, &default_tls_cfg.session_keylog_enable},
237
+	{"session_keylog_filename", PARAM_STR, &default_tls_cfg.session_keylog_filename},
236 238
 	{"config",              PARAM_STR,    &default_tls_cfg.config_file  },
237 239
 	{"tls_disable_compression", PARAM_INT,
238 240
 										&default_tls_cfg.disable_compression},
... ...
@@ -233,6 +233,8 @@ static void tls_options(rpc_t* rpc, void* c)
233 233
 		"cipher_list",		&cfg_get(tls, tls_cfg, cipher_list),
234 234
 		"session_cache",	cfg_get(tls, tls_cfg, session_cache),
235 235
 		"session_id",		&cfg_get(tls, tls_cfg, session_id),
236
+		"session_keylog_enable",	&cfg_get(tls, tls_cfg, session_keylog_enable),
237
+		"session_keylog_filename",	&cfg_get(tls, tls_cfg, session_keylog_filename),
236 238
 		"config",			&cfg_get(tls, tls_cfg, config_file),
237 239
 		"log",				cfg_get(tls, tls_cfg, log),
238 240
 		"debug",			cfg_get(tls, tls_cfg, debug),
... ...
@@ -320,6 +320,7 @@ static int tls_complete_init(struct tcp_connection* c)
320 320
 
321 321
 	/* link the extra data struct inside ssl connection*/
322 322
 	SSL_set_app_data(data->ssl, data);
323
+	set_keylog_callback(data->ssl);
323 324
 	return 0;
324 325
 
325 326
 error:
... ...
@@ -465,6 +466,7 @@ int tls_accept(struct tcp_connection *c, int* error)
465 466
 	if (pkey)
466 467
 		SSL_use_PrivateKey(ssl, pkey);
467 468
 #endif
469
+	set_keylog_callback(ssl);
468 470
 	ret = SSL_accept(ssl);
469 471
 	if (unlikely(ret == 1)) {
470 472
 		DBG("TLS accept successful\n");