Browse code

tls: first interation of session key logger

Sergey Safarov authored on 21/06/2021 12:44:56
Showing 3 changed files
... ...
@@ -571,6 +571,80 @@ 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
+		return 0;
607
+	}
608
+
609
+	if (session_keylog_filename.len == 0) {
610
+		/* Keylogging filename is not specified. */
611
+		return 0;
612
+	}
613
+
614
+	keylog_file = (char *)pkg_malloc((session_keylog_filename.len * sizeof(char) + 1));
615
+	if(keylog_file == NULL) {
616
+		PKG_MEM_ERROR;
617
+		return -1;
618
+	}
619
+	memcpy(keylog_file, session_keylog_filename.s, session_keylog_filename.len);
620
+	keylog_file[session_keylog_filename.len] = 0;
621
+
622
+	/*
623
+	* Append rather than write in order to allow concurrent modification.
624
+	* Furthermore, this preserves existing keylog files which is useful when
625
+	* the tool is run multiple times.
626
+	*/
627
+	bio_keylog = BIO_new_file(keylog_file, "a");
628
+	if (bio_keylog == NULL) {
629
+		LOG(tls_log, "Error writing keylog file: %s\n", keylog_file);
630
+		return 1;
631
+	}
632
+
633
+	/* Write a header for seekable, empty files (this excludes pipes). */
634
+	if (BIO_tell(bio_keylog) == 0) {
635
+		BIO_puts(bio_keylog, "# SSL/TLS secrets log file, generated by Kamailio\n");
636
+		(void)BIO_flush(bio_keylog);
637
+	}
638
+	return 0;
639
+}
640
+
641
+void set_keylog_callback(const SSL *ssl)
642
+{
643
+	if (bio_keylog == NULL) {
644
+		return;
645
+	}
646
+	SSL_CTX_set_keylog_callback(SSL_get_SSL_CTX(ssl), keylog_callback);
647
+}
574 648
 
575 649
 /**
576 650
  * tls pre-init function
... ...
@@ -636,6 +710,7 @@ int tls_h_mod_pre_init_f(void)
636 710
 #endif
637 711
 	SSL_load_error_strings();
638 712
 	tls_mod_preinitialized=1;
713
+	prepare_keylog_file(cfg_get(tls, tls_cfg, session_keylog_filename));
639 714
 	return 0;
640 715
 }
641 716
 
... ...
@@ -865,6 +940,7 @@ int tls_check_sockets(tls_domains_cfg_t* cfg)
865 940
  */
866 941
 void tls_h_mod_destroy_f(void)
867 942
 {
943
+	str str_null = STR_NULL;
868 944
 	LM_DBG("tls module final tls destroy\n");
869 945
 	if(tls_mod_preinitialized > 0)
870 946
 		ERR_free_strings();
... ...
@@ -872,6 +948,7 @@ void tls_h_mod_destroy_f(void)
872 948
 	tls_destroy_cfg();
873 949
 	tls_destroy_locks();
874 950
 	tls_ct_wq_destroy();
951
+	prepare_keylog_file(str_null);
875 952
 #if OPENSSL_VERSION_NUMBER >= 0x010100000L && !defined(LIBRESSL_VERSION_NUMBER)
876 953
 	/* explicit execution of libssl cleanup to avoid being executed again
877 954
 	 * 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 */
... ...
@@ -465,6 +465,7 @@ int tls_accept(struct tcp_connection *c, int* error)
465 465
 	if (pkey)
466 466
 		SSL_use_PrivateKey(ssl, pkey);
467 467
 #endif
468
+	set_keylog_callback(ssl);
468 469
 	ret = SSL_accept(ssl);
469 470
 	if (unlikely(ret == 1)) {
470 471
 		DBG("TLS accept successful\n");