diff --git a/scripts/base/protocols/ssl/main.zeek b/scripts/base/protocols/ssl/main.zeek
index 5b71ebf8b7..eadc4e20fb 100644
--- a/scripts/base/protocols/ssl/main.zeek
+++ b/scripts/base/protocols/ssl/main.zeek
@@ -143,6 +143,10 @@ export {
## (especially with large file transfers).
option disable_analyzer_after_detection = T;
+ ## Maximum length of the ssl_history field to prevent unbounded
+ ## growth when the parser is running into unexpected situations.
+ option max_ssl_history_length = 100;
+
## Delays an SSL record for a specific token: the record will not be
## logged as long as the token exists or until 15 seconds elapses.
global delay_log: function(info: Info, token: string);
@@ -208,10 +212,16 @@ function set_session(c: connection)
function add_to_history(c: connection, is_client: bool, char: string)
{
+ if ( |c$ssl$ssl_history| == max_ssl_history_length )
+ return;
+
if ( is_client )
c$ssl$ssl_history = c$ssl$ssl_history+to_upper(char);
else
c$ssl$ssl_history = c$ssl$ssl_history+to_lower(char);
+
+ if ( |c$ssl$ssl_history| == max_ssl_history_length )
+ Reporter::conn_weird("SSL_max_ssl_history_length_reached", c);
}
function delay_log(info: Info, token: string)
diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output
index 398ce87885..fd0b5bcf0b 100644
--- a/testing/btest/Baseline/plugins.hooks/output
+++ b/testing/btest/Baseline/plugins.hooks/output
@@ -592,6 +592,7 @@
0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (SSH::disable_analyzer_after_detection, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) ->
0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (SSL::ct_logs, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) ->
0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (SSL::disable_analyzer_after_detection, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) ->
+0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (SSL::max_ssl_history_length, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) ->
0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (Signatures::ignored_ids, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) ->
0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (Signatures::summary_interval, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) ->
0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (Site::local_admins, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) ->
@@ -2213,6 +2214,7 @@
0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (SSH::disable_analyzer_after_detection, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100))
0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (SSL::ct_logs, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100))
0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (SSL::disable_analyzer_after_detection, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100))
+0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (SSL::max_ssl_history_length, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100))
0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (Signatures::ignored_ids, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100))
0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (Signatures::summary_interval, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100))
0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (Site::local_admins, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100))
@@ -3833,6 +3835,7 @@
0.000000 | HookCallFunction Option::set_change_handler(SSH::disable_analyzer_after_detection, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)
0.000000 | HookCallFunction Option::set_change_handler(SSL::ct_logs, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)
0.000000 | HookCallFunction Option::set_change_handler(SSL::disable_analyzer_after_detection, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)
+0.000000 | HookCallFunction Option::set_change_handler(SSL::max_ssl_history_length, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)
0.000000 | HookCallFunction Option::set_change_handler(Signatures::ignored_ids, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)
0.000000 | HookCallFunction Option::set_change_handler(Signatures::summary_interval, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)
0.000000 | HookCallFunction Option::set_change_handler(Site::local_admins, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)
diff --git a/testing/btest/Baseline/scripts.base.protocols.ssl.max-history-length/ssl-max-history-length-3.log b/testing/btest/Baseline/scripts.base.protocols.ssl.max-history-length/ssl-max-history-length-3.log
new file mode 100644
index 0000000000..b96373319b
--- /dev/null
+++ b/testing/btest/Baseline/scripts.base.protocols.ssl.max-history-length/ssl-max-history-length-3.log
@@ -0,0 +1,2 @@
+### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
+CHhAvVGS1DHFjwGM9 Csx
diff --git a/testing/btest/Baseline/scripts.base.protocols.ssl.max-history-length/ssl-max-history-length-default.log b/testing/btest/Baseline/scripts.base.protocols.ssl.max-history-length/ssl-max-history-length-default.log
new file mode 100644
index 0000000000..262141044d
--- /dev/null
+++ b/testing/btest/Baseline/scripts.base.protocols.ssl.max-history-length/ssl-max-history-length-default.log
@@ -0,0 +1,2 @@
+### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
+CHhAvVGS1DHFjwGM9 CsxknGIti
diff --git a/testing/btest/Baseline/scripts.base.protocols.ssl.max-history-length/weird-max-history-length-3.log b/testing/btest/Baseline/scripts.base.protocols.ssl.max-history-length/weird-max-history-length-3.log
new file mode 100644
index 0000000000..155cffe1cc
--- /dev/null
+++ b/testing/btest/Baseline/scripts.base.protocols.ssl.max-history-length/weird-max-history-length-3.log
@@ -0,0 +1,2 @@
+### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
+CHhAvVGS1DHFjwGM9 SSL_max_ssl_history_length_reached
diff --git a/testing/btest/scripts/base/protocols/ssl/max-history-length.test b/testing/btest/scripts/base/protocols/ssl/max-history-length.test
new file mode 100644
index 0000000000..41e2ac0889
--- /dev/null
+++ b/testing/btest/scripts/base/protocols/ssl/max-history-length.test
@@ -0,0 +1,12 @@
+# Test max history length functionality
+
+# @TEST-EXEC: zeek -r $TRACES/tls/tls-conn-with-extensions.trace
+# @TEST-EXEC: zeek-cut uid ssl_history < ssl.log > ssl-max-history-length-default.log
+# @TEST-EXEC: btest-diff ssl-max-history-length-default.log
+# @TEST-EXEC: ! test -f weird.log
+#
+# @TEST-EXEC: zeek -r $TRACES/tls/tls-conn-with-extensions.trace SSL::max_ssl_history_length=3
+# @TEST-EXEC: zeek-cut uid ssl_history < ssl.log > ssl-max-history-length-3.log
+# @TEST-EXEC: zeek-cut uid name < weird.log > weird-max-history-length-3.log
+# @TEST-EXEC: btest-diff ssl-max-history-length-3.log
+# @TEST-EXEC: btest-diff weird-max-history-length-3.log