From 8c14b5a911edff7b1ad8dfe1b33fd2c6766aec6d Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Wed, 25 Apr 2012 14:38:11 -0400 Subject: [PATCH 1/9] Added Carrier Grade NAT CIDR and link local IPv6 to "private_address_space" --- scripts/base/utils/site.bro | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/base/utils/site.bro b/scripts/base/utils/site.bro index 4aeb70fe3f..e8db91f3d1 100644 --- a/scripts/base/utils/site.bro +++ b/scripts/base/utils/site.bro @@ -10,8 +10,10 @@ export { const private_address_space: set[subnet] = { 10.0.0.0/8, 192.168.0.0/16, + 172.16.0.0/12, + 100.64.0.0/10, # RFC6598 Carrier Grade NAT 127.0.0.0/8, - 172.16.0.0/12 + [fe80::]/16, } &redef; ## Networks that are considered "local". From c561a44326f696826011f5212501ca09251856fc Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Thu, 26 Apr 2012 10:45:28 -0400 Subject: [PATCH 2/9] Fixed a problem where cluster workers were still processing notices in some cases. --- scripts/base/frameworks/notice/cluster.bro | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/base/frameworks/notice/cluster.bro b/scripts/base/frameworks/notice/cluster.bro index 281901cf31..087c3ead51 100644 --- a/scripts/base/frameworks/notice/cluster.bro +++ b/scripts/base/frameworks/notice/cluster.bro @@ -23,7 +23,10 @@ redef Cluster::worker2manager_events += /Notice::cluster_notice/; @if ( Cluster::local_node_type() != Cluster::MANAGER ) # The notice policy is completely handled by the manager and shouldn't be # done by workers or proxies to save time for packet processing. -redef policy = {}; +event bro_init() &priority=-11 + { + Notice::policy = table(); + } event Notice::begin_suppression(n: Notice::Info) { From 8f91ecee7197329ba7ddc0dbf4cf01831b86e17a Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Fri, 27 Apr 2012 01:24:41 -0400 Subject: [PATCH 3/9] Fixed IPv6 link local unicast CIDR and added IPv6 loopback to private address space. --- scripts/base/utils/site.bro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/base/utils/site.bro b/scripts/base/utils/site.bro index e8db91f3d1..e6afd1c6a5 100644 --- a/scripts/base/utils/site.bro +++ b/scripts/base/utils/site.bro @@ -13,7 +13,8 @@ export { 172.16.0.0/12, 100.64.0.0/10, # RFC6598 Carrier Grade NAT 127.0.0.0/8, - [fe80::]/16, + [fe80::]/10, + [::1]/128, } &redef; ## Networks that are considered "local". From 88807df269d2fab91777b44a3e63e7e8ba0bd8ce Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Fri, 27 Apr 2012 11:32:29 -0400 Subject: [PATCH 4/9] Fixed parsing of TLS server extensions. --- src/ssl-protocol.pac | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ssl-protocol.pac b/src/ssl-protocol.pac index 627645e4da..5bfa2c51f1 100644 --- a/src/ssl-protocol.pac +++ b/src/ssl-protocol.pac @@ -425,6 +425,10 @@ type ServerHello(rec: SSLRecord) = record { session_id : uint8[session_len]; cipher_suite : uint16[1]; compression_method : uint8; + # This weirdness is to deal with the possible existence or absence + # of the following fields. + ext_len: uint16[] &until($element == 0 || $element != 0); + extensions : SSLExtension(rec)[] &until($input.length() == 0); } &let { state_changed : bool = $context.connection.transition(STATE_CLIENT_HELLO_RCVD, From bff3cba129720f208a8931d59861b9e2ba841e83 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Fri, 27 Apr 2012 16:18:14 -0700 Subject: [PATCH 5/9] Add two more TLS extension values that we see in live traffic. - origin_bound_certificates is a current draft http://tools.ietf.org/html/draft-balfanz-tls-obc-01 - encrypted client certificates is a draft that expired yesterday. http://tools.ietf.org/html/draft-agl-tls-encryptedclientcerts-00 --- scripts/base/protocols/ssl/consts.bro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/base/protocols/ssl/consts.bro b/scripts/base/protocols/ssl/consts.bro index 6c33e6e438..42989a4cb9 100644 --- a/scripts/base/protocols/ssl/consts.bro +++ b/scripts/base/protocols/ssl/consts.bro @@ -81,6 +81,8 @@ export { [35] = "SessionTicket TLS", [40] = "extended_random", [13172] = "next_protocol_negotiation", + [13175] = "origin_bound_certificates", + [13180] = "encrypted_client_certificates", [65281] = "renegotiation_info" } &default=function(i: count):string { return fmt("unknown-%d", i); }; From 0a6104fe6615822376db875dce0ee11df38c6f3c Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Thu, 3 May 2012 10:52:24 -0400 Subject: [PATCH 6/9] More bugfixs, cleanup, and test for SSL analyzer - SSL related files and classes renamed to remove the "binpac" term. - A small fix for DPD scripts to make the DPD log more helpful if there are multiple continued failures. Also, fixed the SSL analyzer to make it stop doing repeated violation messages for some handshake failures. - Added a $issuer_subject to the SSL log. - Created a basic test for SSL. --- scripts/base/frameworks/dpd/main.bro | 3 + scripts/base/protocols/ssl/main.bro | 3 + src/Analyzer.cc | 6 +- src/CMakeLists.txt | 2 +- src/{SSL-binpac.cc => SSL.cc} | 17 +++--- src/{SSL-binpac.h => SSL.h} | 13 ++-- src/ssl-analyzer.pac | 56 ++++++++++-------- src/ssl-defs.pac | 29 --------- src/ssl-protocol.pac | 23 ------- .../scripts.base.protocols.ssl.basic/ssl.log | 8 +++ .../Traces/tls-conn-with-extensions.trace | Bin 0 -> 24111 bytes .../scripts/base/protocols/ssl/basic.test | 4 ++ 12 files changed, 68 insertions(+), 96 deletions(-) rename src/{SSL-binpac.cc => SSL.cc} (66%) rename src/{SSL-binpac.h => SSL.h} (74%) create mode 100644 testing/btest/Baseline/scripts.base.protocols.ssl.basic/ssl.log create mode 100644 testing/btest/Traces/tls-conn-with-extensions.trace create mode 100644 testing/btest/scripts/base/protocols/ssl/basic.test diff --git a/scripts/base/frameworks/dpd/main.bro b/scripts/base/frameworks/dpd/main.bro index e8488c3ec1..9eb0b467f8 100644 --- a/scripts/base/frameworks/dpd/main.bro +++ b/scripts/base/frameworks/dpd/main.bro @@ -105,5 +105,8 @@ event protocol_violation(c: connection, atype: count, aid: count, reason: string) &priority=-5 { if ( c?$dpd ) + { Log::write(DPD::LOG, c$dpd); + delete c$dpd; + } } diff --git a/scripts/base/protocols/ssl/main.bro b/scripts/base/protocols/ssl/main.bro index 0b280a6bcf..b5f74d5122 100644 --- a/scripts/base/protocols/ssl/main.bro +++ b/scripts/base/protocols/ssl/main.bro @@ -24,6 +24,8 @@ export { session_id: string &log &optional; ## Subject of the X.509 certificate offered by the server. subject: string &log &optional; + ## Subject of the signer of the X.509 certificate offered by the server. + issuer_subject: string &log &optional; ## NotValidBefore field value from the server certificate. not_valid_before: time &log &optional; ## NotValidAfter field value from the serve certificate. @@ -146,6 +148,7 @@ event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: coun # Also save other certificate information about the primary cert. c$ssl$subject = cert$subject; + c$ssl$issuer_subject = cert$issuer; c$ssl$not_valid_before = cert$not_valid_before; c$ssl$not_valid_after = cert$not_valid_after; } diff --git a/src/Analyzer.cc b/src/Analyzer.cc index 92ca3ecc50..a2a35490e8 100644 --- a/src/Analyzer.cc +++ b/src/Analyzer.cc @@ -34,7 +34,7 @@ #include "Portmap.h" #include "POP3.h" #include "SSH.h" -#include "SSL-binpac.h" +#include "SSL.h" #include "Syslog-binpac.h" #include "ConnSizeAnalyzer.h" @@ -121,8 +121,8 @@ const Analyzer::Config Analyzer::analyzer_configs[] = { HTTP_Analyzer_binpac::InstantiateAnalyzer, HTTP_Analyzer_binpac::Available, 0, false }, { AnalyzerTag::SSL, "SSL", - SSL_Analyzer_binpac::InstantiateAnalyzer, - SSL_Analyzer_binpac::Available, 0, false }, + SSL_Analyzer::InstantiateAnalyzer, + SSL_Analyzer::Available, 0, false }, { AnalyzerTag::SYSLOG_BINPAC, "SYSLOG_BINPAC", Syslog_Analyzer_binpac::InstantiateAnalyzer, Syslog_Analyzer_binpac::Available, 0, false }, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ce1b25dd42..9f9eb8a60f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -376,7 +376,7 @@ set(bro_SRCS SMB.cc SMTP.cc SSH.cc - SSL-binpac.cc + SSL.cc Scope.cc SerializationFormat.cc SerialObj.cc diff --git a/src/SSL-binpac.cc b/src/SSL.cc similarity index 66% rename from src/SSL-binpac.cc rename to src/SSL.cc index db9a7004d6..218b17080b 100644 --- a/src/SSL-binpac.cc +++ b/src/SSL.cc @@ -1,21 +1,21 @@ -#include "SSL-binpac.h" +#include "SSL.h" #include "TCP_Reassembler.h" #include "Reporter.h" #include "util.h" -SSL_Analyzer_binpac::SSL_Analyzer_binpac(Connection* c) +SSL_Analyzer::SSL_Analyzer(Connection* c) : TCP_ApplicationAnalyzer(AnalyzerTag::SSL, c) { interp = new binpac::SSL::SSL_Conn(this); had_gap = false; } -SSL_Analyzer_binpac::~SSL_Analyzer_binpac() +SSL_Analyzer::~SSL_Analyzer() { delete interp; } -void SSL_Analyzer_binpac::Done() +void SSL_Analyzer::Done() { TCP_ApplicationAnalyzer::Done(); @@ -23,23 +23,22 @@ void SSL_Analyzer_binpac::Done() interp->FlowEOF(false); } -void SSL_Analyzer_binpac::EndpointEOF(TCP_Reassembler* endp) +void SSL_Analyzer::EndpointEOF(TCP_Reassembler* endp) { TCP_ApplicationAnalyzer::EndpointEOF(endp); interp->FlowEOF(endp->IsOrig()); } -void SSL_Analyzer_binpac::DeliverStream(int len, const u_char* data, bool orig) +void SSL_Analyzer::DeliverStream(int len, const u_char* data, bool orig) { TCP_ApplicationAnalyzer::DeliverStream(len, data, orig); assert(TCP()); - if ( TCP()->IsPartial() ) return; if ( had_gap ) - // XXX: If only one side had a content gap, we could still try to + // If only one side had a content gap, we could still try to // deliver data to the other side if the script layer can handle this. return; @@ -53,7 +52,7 @@ void SSL_Analyzer_binpac::DeliverStream(int len, const u_char* data, bool orig) } } -void SSL_Analyzer_binpac::Undelivered(int seq, int len, bool orig) +void SSL_Analyzer::Undelivered(int seq, int len, bool orig) { TCP_ApplicationAnalyzer::Undelivered(seq, len, orig); had_gap = true; diff --git a/src/SSL-binpac.h b/src/SSL.h similarity index 74% rename from src/SSL-binpac.h rename to src/SSL.h index 8dab19d00c..c9f8d9be91 100644 --- a/src/SSL-binpac.h +++ b/src/SSL.h @@ -1,14 +1,13 @@ -#ifndef ssl_binpac_h -#define ssl_binpac_h +#ifndef ssl_h +#define ssl_h #include "TCP.h" - #include "ssl_pac.h" -class SSL_Analyzer_binpac : public TCP_ApplicationAnalyzer { +class SSL_Analyzer : public TCP_ApplicationAnalyzer { public: - SSL_Analyzer_binpac(Connection* conn); - virtual ~SSL_Analyzer_binpac(); + SSL_Analyzer(Connection* conn); + virtual ~SSL_Analyzer(); // Overriden from Analyzer. virtual void Done(); @@ -19,7 +18,7 @@ public: virtual void EndpointEOF(TCP_Reassembler* endp); static Analyzer* InstantiateAnalyzer(Connection* conn) - { return new SSL_Analyzer_binpac(conn); } + { return new SSL_Analyzer(conn); } static bool Available() { diff --git a/src/ssl-analyzer.pac b/src/ssl-analyzer.pac index f41fb8639b..32f060adf4 100644 --- a/src/ssl-analyzer.pac +++ b/src/ssl-analyzer.pac @@ -25,6 +25,7 @@ string orig_label(bool is_orig); void free_X509(void *); X509* d2i_X509_binpac(X509** px, const uint8** in, int len); + string handshake_type_label(int type); %} %code{ @@ -46,6 +47,27 @@ string orig_label(bool is_orig) return d2i_X509(px, (u_char**) in, len); #endif } + + string handshake_type_label(int type) + { + switch ( type ) { + case HELLO_REQUEST: return string("HELLO_REQUEST"); + case CLIENT_HELLO: return string("CLIENT_HELLO"); + case SERVER_HELLO: return string("SERVER_HELLO"); + case SESSION_TICKET: return string("SESSION_TICKET"); + case CERTIFICATE: return string("CERTIFICATE"); + case SERVER_KEY_EXCHANGE: return string("SERVER_KEY_EXCHANGE"); + case CERTIFICATE_REQUEST: return string("CERTIFICATE_REQUEST"); + case SERVER_HELLO_DONE: return string("SERVER_HELLO_DONE"); + case CERTIFICATE_VERIFY: return string("CERTIFICATE_VERIFY"); + case CLIENT_KEY_EXCHANGE: return string("CLIENT_KEY_EXCHANGE"); + case FINISHED: return string("FINISHED"); + case CERTIFICATE_URL: return string("CERTIFICATE_URL"); + case CERTIFICATE_STATUS: return string("CERTIFICATE_STATUS"); + default: return string(fmt("UNKNOWN (%d)", type)); + } + } + %} @@ -88,15 +110,15 @@ refine connection SSL_Conn += { eof=0; %} - %eof{ - if ( ! eof && - state_ != STATE_CONN_ESTABLISHED && - state_ != STATE_TRACK_LOST && - state_ != STATE_INITIAL ) - bro_analyzer()->ProtocolViolation(fmt("unexpected end of connection in state %s", - state_label(state_).c_str())); - ++eof; - %} + #%eof{ + # if ( ! eof && + # state_ != STATE_CONN_ESTABLISHED && + # state_ != STATE_TRACK_LOST && + # state_ != STATE_INITIAL ) + # bro_analyzer()->ProtocolViolation(fmt("unexpected end of connection in state %s", + # state_label(state_).c_str())); + # ++eof; + #%} %cleanup{ %} @@ -133,11 +155,6 @@ refine connection SSL_Conn += { cipher_suites16 : uint16[], cipher_suites24 : uint24[]) : bool %{ - if ( state_ == STATE_TRACK_LOST ) - bro_analyzer()->ProtocolViolation(fmt("unexpected client hello message from %s in state %s", - orig_label(${rec.is_orig}).c_str(), - state_label(old_state_).c_str())); - if ( ! version_ok(version) ) bro_analyzer()->ProtocolViolation(fmt("unsupported client SSL version 0x%04x", version)); @@ -175,11 +192,6 @@ refine connection SSL_Conn += { cipher_suites24 : uint24[], comp_method : uint8) : bool %{ - if ( state_ == STATE_TRACK_LOST ) - bro_analyzer()->ProtocolViolation(fmt("unexpected server hello message from %s in state %s", - orig_label(${rec.is_orig}).c_str(), - state_label(old_state_).c_str())); - if ( ! version_ok(version) ) bro_analyzer()->ProtocolViolation(fmt("unsupported server SSL version 0x%04x", version)); else @@ -229,11 +241,6 @@ refine connection SSL_Conn += { function proc_certificate(rec: SSLRecord, certificates : bytestring[]) : bool %{ - if ( state_ == STATE_TRACK_LOST ) - bro_analyzer()->ProtocolViolation(fmt("unexpected certificate message from %s in state %s", - orig_label(${rec.is_orig}).c_str(), - state_label(old_state_).c_str())); - if ( certificates->size() == 0 ) return true; @@ -362,6 +369,7 @@ refine connection SSL_Conn += { handshake_type_label(${hs.msg_type}).c_str(), orig_label(is_orig).c_str(), state_label(old_state_).c_str())); + return true; %} diff --git a/src/ssl-defs.pac b/src/ssl-defs.pac index 31d90338f5..b13b7c4881 100644 --- a/src/ssl-defs.pac +++ b/src/ssl-defs.pac @@ -17,35 +17,6 @@ enum ContentType { UNKNOWN_OR_V2_ENCRYPTED = 400 }; -%code{ - string* record_type_label(int type) - { - switch ( type ) { - case CHANGE_CIPHER_SPEC: - return new string("CHANGE_CIPHER_SPEC"); - case ALERT: - return new string("ALERT"); - case HANDSHAKE: - return new string("HANDSHAKE"); - case APPLICATION_DATA: - return new string("APPLICATION_DATA"); - case V2_ERROR: - return new string("V2_ERROR"); - case V2_CLIENT_HELLO: - return new string("V2_CLIENT_HELLO"); - case V2_CLIENT_MASTER_KEY: - return new string("V2_CLIENT_MASTER_KEY"); - case V2_SERVER_HELLO: - return new string("V2_SERVER_HELLO"); - case UNKNOWN_OR_V2_ENCRYPTED: - return new string("UNKNOWN_OR_V2_ENCRYPTED"); - - default: - return new string(fmt("UNEXPECTED (%d)", type)); - } - } -%} - enum SSLVersions { UNKNOWN_VERSION = 0x0000, SSLv20 = 0x0002, diff --git a/src/ssl-protocol.pac b/src/ssl-protocol.pac index 5bfa2c51f1..0019478518 100644 --- a/src/ssl-protocol.pac +++ b/src/ssl-protocol.pac @@ -23,7 +23,6 @@ type uint24 = record { string state_label(int state_nr); double get_time_from_asn1(const ASN1_TIME * atime); - string handshake_type_label(int type); %} extern type to_int; @@ -268,28 +267,6 @@ enum HandshakeType { CERTIFICATE_STATUS = 22, # RFC 3546 }; -%code{ - string handshake_type_label(int type) - { - switch ( type ) { - case HELLO_REQUEST: return string("HELLO_REQUEST"); - case CLIENT_HELLO: return string("CLIENT_HELLO"); - case SERVER_HELLO: return string("SERVER_HELLO"); - case SESSION_TICKET: return string("SESSION_TICKET"); - case CERTIFICATE: return string("CERTIFICATE"); - case SERVER_KEY_EXCHANGE: return string("SERVER_KEY_EXCHANGE"); - case CERTIFICATE_REQUEST: return string("CERTIFICATE_REQUEST"); - case SERVER_HELLO_DONE: return string("SERVER_HELLO_DONE"); - case CERTIFICATE_VERIFY: return string("CERTIFICATE_VERIFY"); - case CLIENT_KEY_EXCHANGE: return string("CLIENT_KEY_EXCHANGE"); - case FINISHED: return string("FINISHED"); - case CERTIFICATE_URL: return string("CERTIFICATE_URL"); - case CERTIFICATE_STATUS: return string("CERTIFICATE_STATUS"); - default: return string(fmt("UNKNOWN (%d)", type)); - } - } -%} - ###################################################################### # V3 Change Cipher Spec Protocol (7.1.) diff --git a/testing/btest/Baseline/scripts.base.protocols.ssl.basic/ssl.log b/testing/btest/Baseline/scripts.base.protocols.ssl.basic/ssl.log new file mode 100644 index 0000000000..74156362e5 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ssl.basic/ssl.log @@ -0,0 +1,8 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ssl +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher server_name session_id subject issuer_subject not_valid_before not_valid_after last_alert +#types time string addr port addr port string string string string string string time time string +1335538392.319381 UWkUyAuUGXf 192.168.1.105 62045 74.125.224.79 443 TLSv10 TLS_ECDHE_RSA_WITH_RC4_128_SHA ssl.gstatic.com - CN=*.gstatic.com,O=Google Inc,L=Mountain View,ST=California,C=US CN=Google Internet Authority,O=Google Inc,C=US 1334102677.000000 1365639277.000000 - diff --git a/testing/btest/Traces/tls-conn-with-extensions.trace b/testing/btest/Traces/tls-conn-with-extensions.trace new file mode 100644 index 0000000000000000000000000000000000000000..a3b724b3a184e320a93fb23db4c361672e96bdc5 GIT binary patch literal 24111 zcmb@NWmH|s^7aqz?iSqL-JPI81A*WY++Bl9g1c*QcXtcH-62>A65M&u$=uBU&g9N~ zdb3uqus7#acRyA2tM1;LnckWlZ~!FW*T3gy000blu~3t$q#g?iPz3%AY5)w>C?W^* zPu92=$gluO06^riNCY4Pt<2W-3Cu#ydqe3=7pzq&;s_D+;VSUw=aeP@02~sk4h#YU z3=9kwUT{@(1@t>e@IS0qu0jIjfY+e*huuH=09q#j2rLi-0Nl_WnIOxc9>7}9bc5wj z%78r}WutQ&=PLZPo(KsJ3(w@ikPWg9>4vYlQxcOB6Hf|)K z^>RPd0Qz7OpaOr4_XK1aWHDhK5^w=D25P@q-1WKzS)AbepB8Zg=yh@aY7rX(3{Vaf zxflXWDYa%{m>YH6E%Ukrd2%%^a(1*|t$68aIF2=CR!nIg0Fdc|@4^Ix0zv@10G=+C zE+{}CfU^sx3$6>T3j^o~34kep9l+Lw*oE8$-USIr1c(CN2?b#8g6%>FU;{9^kh&nA zo&oUSz#h4Q!^Z@m0{|$Fj#f-&j!p(n7Dh})w${&JAg{v%U;)qo8~`o=4}bsweSsVR zV0Ze%Uli<6f2#VMzc?01e)_B6Z~iI=`m56q6>tI_`-cWVMVo=XIsvH~EC2=g37a9OS3-aY3^F{zbLIA+P|1(=uXh%C^cV;$Nb0;S|W>zLvpk-(+1OT)e09pkA zk;D=J5yuh${*Vm;4h9Ym&vm(^3Nodv$ASb6M;9y;e2oMK1_cFRkzz$)frExnhlIue zS65}lU_k?2z+=Em+uE90nUKiZ7_pMEkbrJNVBr0E)5*la#>9z4)Y-}0*1^Kbo#h1% z5-S@E2P-QJ3kwH3w>I#S{f|pl&?Sr6|Lg}A176&~%EHvv!N$UX6`KVU)DH{>l7g+X zjgx_e4T*+@iR=F!)PFt z;c7

0saKRqAiTI=Wo%Ykf}={U(yWo|Tp|$g&0v&kWy*6lU$rB8eUTJfY%Z zgkeBmb?k_voyd0g^4rbmicrN{OnH5rt2~jHbM_^fum~Kk$w9e~w--GFF&e9dx-_wE z!gk!6Hp66fNqb|}6s9=fK=*^?1%R2b1b`W^5CJDkLJv7AO89Y{EuHF zLt;Z>_BeEXSq%7^BA2RGZcjv~miXY`G5_IIS(`t6`ln0(={}Q@gB6SE zuYrPrL29#Tv1t6dW&!{I*pCwnKWGwYkQ^**0e|�K$KfApnz($=bxp0mzB}y8GX8 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 Fe*mm9@-P4Z literal 0 HcmV?d00001 diff --git a/testing/btest/scripts/base/protocols/ssl/basic.test b/testing/btest/scripts/base/protocols/ssl/basic.test new file mode 100644 index 0000000000..94b0e87ec1 --- /dev/null +++ b/testing/btest/scripts/base/protocols/ssl/basic.test @@ -0,0 +1,4 @@ +# This tests a normal SSL connection and the log it outputs. + +# @TEST-EXEC: bro -r $TRACES/tls-conn-with-extensions.trace %INPUT +# @TEST-EXEC: btest-diff ssl.log From bbac44a6a4b234405a5335dfe8c8ea2beef3f8d6 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 3 May 2012 13:13:58 -0500 Subject: [PATCH 7/9] Changes to open-file caching limits and uncached file unserialization. - Unserializing files that were previously kicked out of the open-file cache would cause them to be fopen'd with the original access permissions which is usually 'w' and causes truncation. They are now opened in 'a' mode. (addresses #780) - Add 'max_files_in_cache' script option to manually set the maximum amount of opened files to keep cached. Mainly this just helped to create a simple test case for the above change. - Remove unused NO_HAVE_SETRLIMIT preprocessor switch. - On systems that don't enforce a limit on number of files opened for the process, raise default max size of open-file cache from 32 to 512. --- scripts/base/init-bare.bro | 5 ++ src/File.cc | 20 ++++---- src/File.h | 8 ++- src/NetVar.cc | 2 + src/NetVar.h | 1 + .../core.file-caching-serialization/one0 | 4 ++ .../core.file-caching-serialization/one1 | 4 ++ .../core.file-caching-serialization/one2 | 4 ++ .../core.file-caching-serialization/two0 | 6 +++ .../core.file-caching-serialization/two1 | 6 +++ .../core.file-caching-serialization/two2 | 6 +++ .../core/file-caching-serialization.test | 49 +++++++++++++++++++ 12 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 testing/btest/Baseline/core.file-caching-serialization/one0 create mode 100644 testing/btest/Baseline/core.file-caching-serialization/one1 create mode 100644 testing/btest/Baseline/core.file-caching-serialization/one2 create mode 100644 testing/btest/Baseline/core.file-caching-serialization/two0 create mode 100644 testing/btest/Baseline/core.file-caching-serialization/two1 create mode 100644 testing/btest/Baseline/core.file-caching-serialization/two2 create mode 100644 testing/btest/core/file-caching-serialization.test diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 8f428b8549..20ce7b8ff5 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2329,6 +2329,11 @@ type bt_tracker_headers: table[string] of string; ## BPF filter the user has set via the -f command line options. Empty if none. const cmd_line_bpf_filter = "" &redef; +## The maximum number of open files to keep cached at a given time. +## If set to zero, this is automatically determined by inspecting +## the current/maximum limit on open files for the process. +const max_files_in_cache = 0 &redef; + ## Deprecated. const log_rotate_interval = 0 sec &redef; diff --git a/src/File.cc b/src/File.cc index d4e31bcc16..4f45c70a58 100644 --- a/src/File.cc +++ b/src/File.cc @@ -74,9 +74,8 @@ void RotateTimer::Dispatch(double t, int is_expire) // The following could in principle be part of a "file manager" object. -#define MAX_FILE_CACHE_SIZE 32 +#define MAX_FILE_CACHE_SIZE 512 static int num_files_in_cache = 0; -static int max_files_in_cache = 0; static BroFile* head = 0; static BroFile* tail = 0; @@ -87,9 +86,6 @@ double BroFile::default_rotation_size = 0; // that we should use for the cache. static int maximize_num_fds() { -#ifdef NO_HAVE_SETRLIMIT - return MAX_FILE_CACHE_SIZE; -#else struct rlimit rl; if ( getrlimit(RLIMIT_NOFILE, &rl) < 0 ) reporter->InternalError("maximize_num_fds(): getrlimit failed"); @@ -111,7 +107,6 @@ static int maximize_num_fds() reporter->InternalError("maximize_num_fds(): setrlimit failed"); return rl.rlim_cur / 2; -#endif } @@ -172,7 +167,7 @@ const char* BroFile::Name() const return 0; } -bool BroFile::Open(FILE* file) +bool BroFile::Open(FILE* file, const char* mode) { open_time = network_time ? network_time : current_time(); @@ -196,7 +191,12 @@ bool BroFile::Open(FILE* file) InstallRotateTimer(); if ( ! f ) - f = fopen(name, access); + { + if ( ! mode ) + f = fopen(name, access); + else + f = fopen(name, mode); + } SetBuf(buffered); @@ -846,8 +846,8 @@ BroFile* BroFile::Unserialize(UnserialInfo* info) } } - // Otherwise, open. - if ( ! file->Open() ) + // Otherwise, open, but don't clobber. + if ( ! file->Open(0, "a") ) { info->s->Error(fmt("cannot open %s: %s", file->name, strerror(errno))); diff --git a/src/File.h b/src/File.h index 444d6209e2..37f844867b 100644 --- a/src/File.h +++ b/src/File.h @@ -87,7 +87,13 @@ protected: BroFile() { Init(); } void Init(); - bool Open(FILE* f = 0); // if file is given, it's an open file to use + + /** + * If file is given, it's an open file to use already. + * If file is not given and mode is, the filename will be opened with that + * access mode. + */ + bool Open(FILE* f = 0, const char* mode = 0); BroFile* Prev() { return prev; } BroFile* Next() { return next; } diff --git a/src/NetVar.cc b/src/NetVar.cc index 59cc1cc633..bdb566b20b 100644 --- a/src/NetVar.cc +++ b/src/NetVar.cc @@ -167,6 +167,7 @@ TableVal* preserve_orig_addr; TableVal* preserve_resp_addr; TableVal* preserve_other_addr; +int max_files_in_cache; double log_rotate_interval; double log_max_size; RecordType* rotate_info; @@ -257,6 +258,7 @@ void init_general_global_var() state_dir = internal_val("state_dir")->AsStringVal(); state_write_delay = opt_internal_double("state_write_delay"); + max_files_in_cache = opt_internal_int("max_files_in_cache"); log_rotate_interval = opt_internal_double("log_rotate_interval"); log_max_size = opt_internal_double("log_max_size"); rotate_info = internal_type("rotate_info")->AsRecordType(); diff --git a/src/NetVar.h b/src/NetVar.h index 425ea93e09..a7e750dc59 100644 --- a/src/NetVar.h +++ b/src/NetVar.h @@ -170,6 +170,7 @@ extern double connection_status_update_interval; extern StringVal* state_dir; extern double state_write_delay; +extern int max_files_in_cache; extern double log_rotate_interval; extern double log_max_size; extern RecordType* rotate_info; diff --git a/testing/btest/Baseline/core.file-caching-serialization/one0 b/testing/btest/Baseline/core.file-caching-serialization/one0 new file mode 100644 index 0000000000..abfe9a2af6 --- /dev/null +++ b/testing/btest/Baseline/core.file-caching-serialization/one0 @@ -0,0 +1,4 @@ +opened +write 0 +write 3 +write 6 diff --git a/testing/btest/Baseline/core.file-caching-serialization/one1 b/testing/btest/Baseline/core.file-caching-serialization/one1 new file mode 100644 index 0000000000..d53edaed28 --- /dev/null +++ b/testing/btest/Baseline/core.file-caching-serialization/one1 @@ -0,0 +1,4 @@ +opened +write 1 +write 4 +write 7 diff --git a/testing/btest/Baseline/core.file-caching-serialization/one2 b/testing/btest/Baseline/core.file-caching-serialization/one2 new file mode 100644 index 0000000000..5b5c9bc130 --- /dev/null +++ b/testing/btest/Baseline/core.file-caching-serialization/one2 @@ -0,0 +1,4 @@ +opened +write 2 +write 5 +write 8 diff --git a/testing/btest/Baseline/core.file-caching-serialization/two0 b/testing/btest/Baseline/core.file-caching-serialization/two0 new file mode 100644 index 0000000000..88e273032e --- /dev/null +++ b/testing/btest/Baseline/core.file-caching-serialization/two0 @@ -0,0 +1,6 @@ +opened +write 0 +opened +write 3 +opened +write 6 diff --git a/testing/btest/Baseline/core.file-caching-serialization/two1 b/testing/btest/Baseline/core.file-caching-serialization/two1 new file mode 100644 index 0000000000..b2f9350bc4 --- /dev/null +++ b/testing/btest/Baseline/core.file-caching-serialization/two1 @@ -0,0 +1,6 @@ +opened +write 1 +opened +write 4 +opened +write 7 diff --git a/testing/btest/Baseline/core.file-caching-serialization/two2 b/testing/btest/Baseline/core.file-caching-serialization/two2 new file mode 100644 index 0000000000..94a971c7db --- /dev/null +++ b/testing/btest/Baseline/core.file-caching-serialization/two2 @@ -0,0 +1,6 @@ +opened +write 2 +opened +write 5 +opened +write 8 diff --git a/testing/btest/core/file-caching-serialization.test b/testing/btest/core/file-caching-serialization.test new file mode 100644 index 0000000000..7ff1d8be8d --- /dev/null +++ b/testing/btest/core/file-caching-serialization.test @@ -0,0 +1,49 @@ +# This checks that the interactions between open-file caching and +# serialization works ok. In the first case, all files can fit +# in the cache, but get serialized before every write. In the +# second case, files are eventually forced out of the cache and +# undergo serialization, which requires re-opening. + +# @TEST-EXEC: bro -b %INPUT "test_file_prefix=one" +# @TEST-EXEC: btest-diff one0 +# @TEST-EXEC: btest-diff one1 +# @TEST-EXEC: btest-diff one2 +# @TEST-EXEC: bro -b %INPUT "test_file_prefix=two" "max_files_in_cache=2" +# @TEST-EXEC: btest-diff two0 +# @TEST-EXEC: btest-diff two1 +# @TEST-EXEC: btest-diff two2 + +const test_file_prefix = "" &redef; +global file_table: table[string] of file; +global iterations: vector of count = vector(0,1,2,3,4,5,6,7,8); + +function write_to_file(c: count) + { + local f: file; + # Take turns writing across three output files. + local filename = fmt("%s%s", test_file_prefix, c % 3 ); + + if ( filename in file_table ) + f = file_table[filename]; + else + { + f = open(filename); + file_table[filename] = f; + } + + # This when block is a trick to get the frame cloned + # and thus serialize the local file value + when ( local s = fmt("write %d", c) ) + print f, s; + } + +event file_opened(f: file) + { + print f, "opened"; + } + +event bro_init() + { + for ( i in iterations ) + write_to_file(iterations[i]); + } From c9b53706a15db9a0077bdffde2865bd36ad621b7 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 3 May 2012 11:45:11 -0700 Subject: [PATCH 8/9] Updating submodule(s). [nomail] --- aux/broctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/broctl b/aux/broctl index 22df444f54..76e6bd4b18 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit 22df444f54d8cbc05976ef4a5524c73a45ab6372 +Subproject commit 76e6bd4b182e9ff43456890e08aeaf451f9e4615 From 79afc834ce4218ac986c16dffa5f835fa3b7b6a2 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 4 May 2012 16:09:05 -0500 Subject: [PATCH 9/9] Add SHA1 and SHA256 hashing BIFs. (addresses #542) Also refactor all internal MD5 stuff to use OpenSSL's. --- src/Anon.cc | 1 - src/CMakeLists.txt | 6 +- src/DFA.cc | 15 +- src/Func.cc | 1 - src/MIME.cc | 5 +- src/MIME.h | 5 +- src/bro.bif | 301 ++++++++++++++++- src/digest.h | 92 ++++++ src/main.cc | 5 +- src/md5.c | 380 ---------------------- src/md5.h | 90 ----- src/util.cc | 27 +- src/util.h | 4 - testing/btest/Baseline/bifs.md5/output | 4 + testing/btest/Baseline/bifs.sha1/output | 4 + testing/btest/Baseline/bifs.sha256/output | 4 + testing/btest/bifs/md5.test | 16 + testing/btest/bifs/sha1.test | 16 + testing/btest/bifs/sha256.test | 16 + 19 files changed, 461 insertions(+), 531 deletions(-) create mode 100644 src/digest.h delete mode 100644 src/md5.c delete mode 100644 src/md5.h create mode 100644 testing/btest/Baseline/bifs.md5/output create mode 100644 testing/btest/Baseline/bifs.sha1/output create mode 100644 testing/btest/Baseline/bifs.sha256/output create mode 100644 testing/btest/bifs/md5.test create mode 100644 testing/btest/bifs/sha1.test create mode 100644 testing/btest/bifs/sha256.test diff --git a/src/Anon.cc b/src/Anon.cc index d2a28a0e08..f58057b2fc 100644 --- a/src/Anon.cc +++ b/src/Anon.cc @@ -5,7 +5,6 @@ #include "util.h" #include "net_util.h" -#include "md5.h" #include "Anon.h" #include "Val.h" #include "NetVar.h" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ce1b25dd42..4e73ad69b4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -247,7 +247,6 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/DebugCmdConstants.h WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) -set(dns_SRCS nb_dns.c) set_source_files_properties(nb_dns.c PROPERTIES COMPILE_FLAGS -fno-strict-aliasing) @@ -403,7 +402,6 @@ set(bro_SRCS bsd-getopt-long.c bro_inet_ntop.c cq.c - md5.c patricia.c setsignal.c PacketDumper.cc @@ -421,8 +419,8 @@ set(bro_SRCS logging/writers/Ascii.cc logging/writers/None.cc - ${dns_SRCS} - ${openssl_SRCS} + nb_dns.c + digest.h ) collect_headers(bro_HEADERS ${bro_SRCS}) diff --git a/src/DFA.cc b/src/DFA.cc index e58ea260e5..06ccfd9342 100644 --- a/src/DFA.cc +++ b/src/DFA.cc @@ -2,9 +2,10 @@ #include "config.h" +#include + #include "EquivClass.h" #include "DFA.h" -#include "md5.h" int dfa_state_cache_size = 10000; @@ -312,8 +313,8 @@ DFA_State* DFA_State_Cache::Lookup(const NFA_state_list& nfas, { // We assume that state ID's don't exceed 10 digits, plus // we allow one more character for the delimiter. - md5_byte_t id_tag[nfas.length() * 11 + 1]; - md5_byte_t* p = id_tag; + u_char id_tag[nfas.length() * 11 + 1]; + u_char* p = id_tag; for ( int i = 0; i < nfas.length(); ++i ) { @@ -335,12 +336,8 @@ DFA_State* DFA_State_Cache::Lookup(const NFA_state_list& nfas, // We use the short MD5 instead of the full string for the // HashKey because the data is copied into the key. - md5_state_t state; - md5_byte_t digest[16]; - - md5_init(&state); - md5_append(&state, id_tag, p - id_tag); - md5_finish(&state, digest); + u_char digest[16]; + MD5(id_tag, p - id_tag, digest); *hash = new HashKey(&digest, sizeof(digest)); CacheEntry* e = states.Lookup(*hash); diff --git a/src/Func.cc b/src/Func.cc index 65cb22b09d..ecb341e3e0 100644 --- a/src/Func.cc +++ b/src/Func.cc @@ -29,7 +29,6 @@ #include -#include "md5.h" #include "Base64.h" #include "Stmt.h" #include "Scope.h" diff --git a/src/MIME.cc b/src/MIME.cc index 103cf149ef..4a7c0268b0 100644 --- a/src/MIME.cc +++ b/src/MIME.cc @@ -4,6 +4,7 @@ #include "MIME.h" #include "Event.h" #include "Reporter.h" +#include "digest.h" // Here are a few things to do: // @@ -1008,7 +1009,7 @@ void MIME_Mail::Done() if ( compute_content_hash && mime_content_hash ) { u_char* digest = new u_char[16]; - md5_finish(&md5_hash, digest); + md5_final(&md5_hash, digest); val_list* vl = new val_list; vl->append(analyzer->BuildConnVal()); @@ -1096,7 +1097,7 @@ void MIME_Mail::SubmitData(int len, const char* buf) if ( compute_content_hash ) { content_hash_length += len; - md5_append(&md5_hash, (const u_char*) buf, len); + md5_update(&md5_hash, (const u_char*) buf, len); } if ( mime_entity_data || mime_all_data ) diff --git a/src/MIME.h b/src/MIME.h index 52d943fb15..ffff30e387 100644 --- a/src/MIME.h +++ b/src/MIME.h @@ -2,13 +2,12 @@ #define mime_h #include - +#include #include #include #include using namespace std; -#include "md5.h" #include "Base64.h" #include "BroString.h" #include "Analyzer.h" @@ -248,7 +247,7 @@ protected: int buffer_offset; int compute_content_hash; int content_hash_length; - md5_state_t md5_hash; + MD5_CTX md5_hash; vector entity_content; vector all_content; diff --git a/src/bro.bif b/src/bro.bif index f76704cfe6..15740a83c7 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -6,13 +6,13 @@ %%{ // C segment #include - #include #include #include #include #include +#include "digest.h" #include "Reporter.h" #include "IPAddr.h" @@ -530,7 +530,7 @@ function piped_exec%(program: string, to_write: string%): bool %%{ static void hash_md5_val(val_list& vlist, unsigned char digest[16]) { - md5_state_s h; + MD5_CTX h; md5_init(&h); loop_over_list(vlist, i) @@ -539,16 +539,16 @@ static void hash_md5_val(val_list& vlist, unsigned char digest[16]) if ( v->Type()->Tag() == TYPE_STRING ) { const BroString* str = v->AsString(); - md5_append(&h, str->Bytes(), str->Len()); + md5_update(&h, str->Bytes(), str->Len()); } else { ODesc d(DESC_BINARY); v->Describe(&d); - md5_append(&h, (const md5_byte_t *) d.Bytes(), d.Len()); + md5_update(&h, (const u_char *) d.Bytes(), d.Len()); } } - md5_finish(&h, digest); + md5_final(&h, digest); } static void hmac_md5_val(val_list& vlist, unsigned char digest[16]) @@ -556,7 +556,53 @@ static void hmac_md5_val(val_list& vlist, unsigned char digest[16]) hash_md5_val(vlist, digest); for ( int i = 0; i < 16; ++i ) digest[i] = digest[i] ^ shared_hmac_md5_key[i]; - hash_md5(16, digest, digest); + MD5(digest, 16, digest); + } + +static void hash_sha1_val(val_list& vlist, unsigned char digest[20]) + { + SHA_CTX h; + + sha1_init(&h); + loop_over_list(vlist, i) + { + Val* v = vlist[i]; + if ( v->Type()->Tag() == TYPE_STRING ) + { + const BroString* str = v->AsString(); + sha1_update(&h, str->Bytes(), str->Len()); + } + else + { + ODesc d(DESC_BINARY); + v->Describe(&d); + sha1_update(&h, (const u_char *) d.Bytes(), d.Len()); + } + } + sha1_final(&h, digest); + } + +static void hash_sha256_val(val_list& vlist, unsigned char digest[32]) + { + SHA256_CTX h; + + sha256_init(&h); + loop_over_list(vlist, i) + { + Val* v = vlist[i]; + if ( v->Type()->Tag() == TYPE_STRING ) + { + const BroString* str = v->AsString(); + sha256_update(&h, str->Bytes(), str->Len()); + } + else + { + ODesc d(DESC_BINARY); + v->Describe(&d); + sha256_update(&h, (const u_char *) d.Bytes(), d.Len()); + } + } + sha256_final(&h, digest); } %%} @@ -565,6 +611,8 @@ static void hmac_md5_val(val_list& vlist, unsigned char digest[16]) ## Returns: The MD5 hash value of the concatenated arguments. ## ## .. bro:see:: md5_hmac md5_hash_init md5_hash_update md5_hash_finish +## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish +## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish ## ## .. note:: ## @@ -578,6 +626,46 @@ function md5_hash%(...%): string return new StringVal(md5_digest_print(digest)); %} +## Computes the SHA1 hash value of the provided list of arguments. +## +## Returns: The SHA1 hash value of the concatenated arguments. +## +## .. bro:see:: md5_hash md5_hmac md5_hash_init md5_hash_update md5_hash_finish +## sha1_hash_init sha1_hash_update sha1_hash_finish +## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish +## +## .. note:: +## +## This function performs a one-shot computation of its arguments. +## For incremental hash computation, see :bro:id:`sha1_hash_init` and +## friends. +function sha1_hash%(...%): string + %{ + unsigned char digest[20]; + hash_sha1_val(@ARG@, digest); + return new StringVal(sha1_digest_print(digest)); + %} + +## Computes the SHA256 hash value of the provided list of arguments. +## +## Returns: The SHA256 hash value of the concatenated arguments. +## +## .. bro:see:: md5_hash md5_hmac md5_hash_init md5_hash_update md5_hash_finish +## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish +## sha256_hash_init sha256_hash_update sha256_hash_finish +## +## .. note:: +## +## This function performs a one-shot computation of its arguments. +## For incremental hash computation, see :bro:id:`sha256_hash_init` and +## friends. +function sha256_hash%(...%): string + %{ + unsigned char digest[32]; + hash_sha256_val(@ARG@, digest); + return new StringVal(sha256_digest_print(digest)); + %} + ## Computes an HMAC-MD5 hash value of the provided list of arguments. The HMAC ## secret key is generated from available entropy when Bro starts up, or it can ## be specified for repeatability using the ``-K`` command line flag. @@ -585,6 +673,8 @@ function md5_hash%(...%): string ## Returns: The HMAC-MD5 hash value of the concatenated arguments. ## ## .. bro:see:: md5_hash md5_hash_init md5_hash_update md5_hash_finish +## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish +## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish function md5_hmac%(...%): string %{ unsigned char digest[16]; @@ -593,7 +683,9 @@ function md5_hmac%(...%): string %} %%{ -static map md5_states; +static map md5_states; +static map sha1_states; +static map sha256_states; BroString* convert_index_to_string(Val* index) { @@ -618,7 +710,9 @@ BroString* convert_index_to_string(Val* index) ## ## index: The unique identifier to associate with this hash computation. ## -## .. bro:see:: md5_hash md5_hmac md5_hash_update md5_hash_finish +## .. bro:see:: md5_hmac md5_hash md5_hash_update md5_hash_finish +## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish +## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish function md5_hash_init%(index: any%): bool %{ BroString* s = convert_index_to_string(index); @@ -626,7 +720,7 @@ function md5_hash_init%(index: any%): bool if ( md5_states.count(*s) < 1 ) { - md5_state_s h; + MD5_CTX h; md5_init(&h); md5_states[*s] = h; status = 1; @@ -636,6 +730,75 @@ function md5_hash_init%(index: any%): bool return new Val(status, TYPE_BOOL); %} +## Initializes SHA1 state to enable incremental hash computation. After +## initializing the SHA1 state with this function, you can feed data to +## :bro:id:`sha1_hash_update` and finally need to call +## :bro:id:`sha1_hash_finish` to finish the computation and get the final hash +## value. +## +## For example, when computing incremental SHA1 values of transferred files in +## multiple concurrent HTTP connections, one would call ``sha1_hash_init(c$id)`` +## once before invoking ``sha1_hash_update(c$id, some_more_data)`` in the +## :bro:id:`http_entity_data` event handler. When all data has arrived, a call +## to :bro:id:`sha1_hash_finish` returns the final hash value. +## +## index: The unique identifier to associate with this hash computation. +## +## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish +## sha1_hash sha1_hash_update sha1_hash_finish +## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish +function sha1_hash_init%(index: any%): bool + %{ + BroString* s = convert_index_to_string(index); + int status = 0; + + if ( sha1_states.count(*s) < 1 ) + { + SHA_CTX h; + sha1_init(&h); + sha1_states[*s] = h; + status = 1; + } + + delete s; + return new Val(status, TYPE_BOOL); + %} + +## Initializes SHA256 state to enable incremental hash computation. After +## initializing the SHA256 state with this function, you can feed data to +## :bro:id:`sha256_hash_update` and finally need to call +## :bro:id:`sha256_hash_finish` to finish the computation and get the final hash +## value. +## +## For example, when computing incremental SHA256 values of transferred files in +## multiple concurrent HTTP connections, one would call +## ``sha256_hash_init(c$id)`` once before invoking +## ``sha256_hash_update(c$id, some_more_data)`` in the +## :bro:id:`http_entity_data` event handler. When all data has arrived, a call +## to :bro:id:`sha256_hash_finish` returns the final hash value. +## +## index: The unique identifier to associate with this hash computation. +## +## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish +## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish +## sha256_hash sha256_hash_update sha256_hash_finish +function sha256_hash_init%(index: any%): bool + %{ + BroString* s = convert_index_to_string(index); + int status = 0; + + if ( sha256_states.count(*s) < 1 ) + { + SHA256_CTX h; + sha256_init(&h); + sha256_states[*s] = h; + status = 1; + } + + delete s; + return new Val(status, TYPE_BOOL); + %} + ## Update the MD5 value associated with a given index. It is required to ## call :bro:id:`md5_hash_init` once before calling this ## function. @@ -644,7 +807,9 @@ function md5_hash_init%(index: any%): bool ## ## data: The data to add to the hash computation. ## -## .. bro:see:: md5_hash md5_hmac md5_hash_init md5_hash_finish +## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_finish +## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish +## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish function md5_hash_update%(index: any, data: string%): bool %{ BroString* s = convert_index_to_string(index); @@ -652,7 +817,59 @@ function md5_hash_update%(index: any, data: string%): bool if ( md5_states.count(*s) > 0 ) { - md5_append(&md5_states[*s], data->Bytes(), data->Len()); + md5_update(&md5_states[*s], data->Bytes(), data->Len()); + status = 1; + } + + delete s; + return new Val(status, TYPE_BOOL); + %} + +## Update the SHA1 value associated with a given index. It is required to +## call :bro:id:`sha1_hash_init` once before calling this +## function. +## +## index: The unique identifier to associate with this hash computation. +## +## data: The data to add to the hash computation. +## +## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish +## sha1_hash sha1_hash_init sha1_hash_finish +## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish +function sha1_hash_update%(index: any, data: string%): bool + %{ + BroString* s = convert_index_to_string(index); + int status = 0; + + if ( sha1_states.count(*s) > 0 ) + { + sha1_update(&sha1_states[*s], data->Bytes(), data->Len()); + status = 1; + } + + delete s; + return new Val(status, TYPE_BOOL); + %} + +## Update the SHA256 value associated with a given index. It is required to +## call :bro:id:`sha256_hash_init` once before calling this +## function. +## +## index: The unique identifier to associate with this hash computation. +## +## data: The data to add to the hash computation. +## +## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish +## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish +## sha256_hash sha256_hash_init sha256_hash_finish +function sha256_hash_update%(index: any, data: string%): bool + %{ + BroString* s = convert_index_to_string(index); + int status = 0; + + if ( sha256_states.count(*s) > 0 ) + { + sha256_update(&sha256_states[*s], data->Bytes(), data->Len()); status = 1; } @@ -666,7 +883,9 @@ function md5_hash_update%(index: any, data: string%): bool ## ## Returns: The hash value associated with the computation at *index*. ## -## .. bro:see:: md5_hash md5_hmac md5_hash_init md5_hash_update +## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update +## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish +## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish function md5_hash_finish%(index: any%): string %{ BroString* s = convert_index_to_string(index); @@ -675,7 +894,7 @@ function md5_hash_finish%(index: any%): string if ( md5_states.count(*s) > 0 ) { unsigned char digest[16]; - md5_finish(&md5_states[*s], digest); + md5_final(&md5_states[*s], digest); md5_states.erase(*s); printable_digest = new StringVal(md5_digest_print(digest)); } @@ -686,6 +905,62 @@ function md5_hash_finish%(index: any%): string return printable_digest; %} +## Returns the final SHA1 digest of an incremental hash computation. +## +## index: The unique identifier of this hash computation. +## +## Returns: The hash value associated with the computation at *index*. +## +## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish +## sha1_hash sha1_hash_init sha1_hash_update +## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish +function sha1_hash_finish%(index: any%): string + %{ + BroString* s = convert_index_to_string(index); + StringVal* printable_digest; + + if ( sha1_states.count(*s) > 0 ) + { + unsigned char digest[20]; + sha1_final(&sha1_states[*s], digest); + sha1_states.erase(*s); + printable_digest = new StringVal(sha1_digest_print(digest)); + } + else + printable_digest = new StringVal(""); + + delete s; + return printable_digest; + %} + +## Returns the final SHA256 digest of an incremental hash computation. +## +## index: The unique identifier of this hash computation. +## +## Returns: The hash value associated with the computation at *index*. +## +## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish +## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish +## sha256_hash sha256_hash_init sha256_hash_update +function sha256_hash_finish%(index: any%): string + %{ + BroString* s = convert_index_to_string(index); + StringVal* printable_digest; + + if ( sha256_states.count(*s) > 0 ) + { + unsigned char digest[32]; + sha256_final(&sha256_states[*s], digest); + sha256_states.erase(*s); + printable_digest = new StringVal(sha256_digest_print(digest)); + } + else + printable_digest = new StringVal(""); + + delete s; + return printable_digest; + %} + ## Generates a random number. ## ## max: The maximum value the random number. diff --git a/src/digest.h b/src/digest.h new file mode 100644 index 0000000000..ef52ba059a --- /dev/null +++ b/src/digest.h @@ -0,0 +1,92 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +/** + * Wrapper and helper functions for MD5/SHA digest algorithms. + */ + +#ifndef bro_digest_h +#define bro_digest_h + +#include +#include + +#include "Reporter.h" + +static inline const char* digest_print(const u_char* digest, size_t n) + { + static char buf[256]; // big enough for any of md5/sha1/sha256 + for ( size_t i = 0; i < n; ++i ) + snprintf(buf + i * 2, 3, "%02x", digest[i]); + return buf; + } + +inline const char* md5_digest_print(const u_char digest[MD5_DIGEST_LENGTH]) + { + return digest_print(digest, MD5_DIGEST_LENGTH); + } + +inline const char* sha1_digest_print(const u_char digest[SHA_DIGEST_LENGTH]) + { + return digest_print(digest, SHA_DIGEST_LENGTH); + } + +inline const char* sha256_digest_print(const u_char digest[SHA256_DIGEST_LENGTH]) + { + return digest_print(digest, SHA256_DIGEST_LENGTH); + } + +inline void md5_init(MD5_CTX* c) + { + if ( ! MD5_Init(c) ) + reporter->InternalError("MD5_Init failed"); + } + +inline void md5_update(MD5_CTX* c, const void* data, unsigned long len) + { + if ( ! MD5_Update(c, data, len) ) + reporter->InternalError("MD5_Update failed"); + } + +inline void md5_final(MD5_CTX* c, u_char md[MD5_DIGEST_LENGTH]) + { + if ( ! MD5_Final(md, c) ) + reporter->InternalError("MD5_Final failed"); + } + +inline void sha1_init(SHA_CTX* c) + { + if ( ! SHA1_Init(c) ) + reporter->InternalError("SHA_Init failed"); + } + +inline void sha1_update(SHA_CTX* c, const void* data, unsigned long len) + { + if ( ! SHA1_Update(c, data, len) ) + reporter->InternalError("SHA_Update failed"); + } + +inline void sha1_final(SHA_CTX* c, u_char md[SHA_DIGEST_LENGTH]) + { + if ( ! SHA1_Final(md, c) ) + reporter->InternalError("SHA_Final failed"); + } + +inline void sha256_init(SHA256_CTX* c) + { + if ( ! SHA256_Init(c) ) + reporter->InternalError("SHA256_Init failed"); + } + +inline void sha256_update(SHA256_CTX* c, const void* data, unsigned long len) + { + if ( ! SHA256_Update(c, data, len) ) + reporter->InternalError("SHA256_Update failed"); + } + +inline void sha256_final(SHA256_CTX* c, u_char md[SHA256_DIGEST_LENGTH]) + { + if ( ! SHA256_Final(md, c) ) + reporter->InternalError("SHA256_Final failed"); + } + +#endif //bro_digest_h diff --git a/src/main.cc b/src/main.cc index ff33a3859d..89783031bf 100644 --- a/src/main.cc +++ b/src/main.cc @@ -18,6 +18,8 @@ extern "C" { } #endif +#include + extern "C" void OPENSSL_add_all_algorithms_conf(void); #include "bsd-getopt-long.h" @@ -570,8 +572,7 @@ int main(int argc, char** argv) break; case 'K': - hash_md5(strlen(optarg), (const u_char*) optarg, - shared_hmac_md5_key); + MD5((const u_char*) optarg, strlen(optarg), shared_hmac_md5_key); hmac_key_set = 1; break; diff --git a/src/md5.c b/src/md5.c deleted file mode 100644 index 888993b9c4..0000000000 --- a/src/md5.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -#include "md5.h" -#include - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -#ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -# define BYTE_ORDER 0 -#endif - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; -#endif - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} diff --git a/src/md5.h b/src/md5.h deleted file mode 100644 index 2806b5b9b5..0000000000 --- a/src/md5.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.h is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . - 1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -# define md5_INCLUDED - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Initialize the algorithm. */ -void md5_init(md5_state_t *pms); - -/* Append a string to the message. */ -void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); - -/* Finish the message and return the digest. */ -void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */ diff --git a/src/util.cc b/src/util.cc index 856e90d156..90143923f1 100644 --- a/src/util.cc +++ b/src/util.cc @@ -27,6 +27,8 @@ #include #include #include +#include +#include #ifdef HAVE_MALLINFO # include @@ -35,7 +37,6 @@ #include "input.h" #include "util.h" #include "Obj.h" -#include "md5.h" #include "Val.h" #include "NetVar.h" #include "Net.h" @@ -546,24 +547,6 @@ bool is_dir(const char* path) return S_ISDIR(st.st_mode); } -void hash_md5(size_t size, const unsigned char* bytes, unsigned char digest[16]) - { - md5_state_s h; - md5_init(&h); - md5_append(&h, bytes, size); - md5_finish(&h, digest); - } - -const char* md5_digest_print(const unsigned char digest[16]) - { - static char digest_print[256]; - - for ( int i = 0; i < 16; ++i ) - snprintf(digest_print + i * 2, 3, "%02x", digest[i]); - - return digest_print; - } - int hmac_key_set = 0; uint8 shared_hmac_md5_key[16]; @@ -572,12 +555,12 @@ void hmac_md5(size_t size, const unsigned char* bytes, unsigned char digest[16]) if ( ! hmac_key_set ) reporter->InternalError("HMAC-MD5 invoked before the HMAC key is set"); - hash_md5(size, bytes, digest); + MD5(bytes, size, digest); for ( int i = 0; i < 16; ++i ) digest[i] ^= shared_hmac_md5_key[i]; - hash_md5(16, digest, digest); + MD5(digest, 16, digest); } static bool read_random_seeds(const char* read_file, uint32* seed, @@ -724,7 +707,7 @@ void init_random_seed(uint32 seed, const char* read_file, const char* write_file if ( ! hmac_key_set ) { - hash_md5(sizeof(buf), (u_char*) buf, shared_hmac_md5_key); + MD5((const u_char*) buf, sizeof(buf), shared_hmac_md5_key); hmac_key_set = 1; } diff --git a/src/util.h b/src/util.h index a4e3aa71b8..6b237edfd8 100644 --- a/src/util.h +++ b/src/util.h @@ -136,16 +136,12 @@ extern bool ensure_dir(const char *dirname); bool is_dir(const char* path); extern uint8 shared_hmac_md5_key[16]; -extern void hash_md5(size_t size, const unsigned char* bytes, - unsigned char digest[16]); extern int hmac_key_set; extern unsigned char shared_hmac_md5_key[16]; extern void hmac_md5(size_t size, const unsigned char* bytes, unsigned char digest[16]); -extern const char* md5_digest_print(const unsigned char digest[16]); - // Initializes RNGs for bro_random() and MD5 usage. If seed is given, then // it is used (to provide determinism). If load_file is given, the seeds // (both random & MD5) are loaded from that file. This takes precedence diff --git a/testing/btest/Baseline/bifs.md5/output b/testing/btest/Baseline/bifs.md5/output new file mode 100644 index 0000000000..71c0fbfcb8 --- /dev/null +++ b/testing/btest/Baseline/bifs.md5/output @@ -0,0 +1,4 @@ +f97c5d29941bfb1b2fdab0874906ab82 +7b0391feb2e0cd271f1cf39aafb4376f +f97c5d29941bfb1b2fdab0874906ab82 +7b0391feb2e0cd271f1cf39aafb4376f diff --git a/testing/btest/Baseline/bifs.sha1/output b/testing/btest/Baseline/bifs.sha1/output new file mode 100644 index 0000000000..ddcf9060b9 --- /dev/null +++ b/testing/btest/Baseline/bifs.sha1/output @@ -0,0 +1,4 @@ +fe05bcdcdc4928012781a5f1a2a77cbb5398e106 +3e949019500deb1369f13d9644d420d3a920aa5e +fe05bcdcdc4928012781a5f1a2a77cbb5398e106 +3e949019500deb1369f13d9644d420d3a920aa5e diff --git a/testing/btest/Baseline/bifs.sha256/output b/testing/btest/Baseline/bifs.sha256/output new file mode 100644 index 0000000000..5bd6a63fa4 --- /dev/null +++ b/testing/btest/Baseline/bifs.sha256/output @@ -0,0 +1,4 @@ +7692c3ad3540bb803c020b3aee66cd8887123234ea0c6e7143c0add73ff431ed +4592092e1061c7ea85af2aed194621cc17a2762bae33a79bf8ce33fd0168b801 +7692c3ad3540bb803c020b3aee66cd8887123234ea0c6e7143c0add73ff431ed +4592092e1061c7ea85af2aed194621cc17a2762bae33a79bf8ce33fd0168b801 diff --git a/testing/btest/bifs/md5.test b/testing/btest/bifs/md5.test new file mode 100644 index 0000000000..2632d76cb4 --- /dev/null +++ b/testing/btest/bifs/md5.test @@ -0,0 +1,16 @@ +# @TEST-EXEC: bro -b %INPUT >output +# @TEST-EXEC: btest-diff output + +print md5_hash("one"); +print md5_hash("one", "two", "three"); + +md5_hash_init("a"); +md5_hash_init("b"); + +md5_hash_update("a", "one"); +md5_hash_update("b", "one"); +md5_hash_update("b", "two"); +md5_hash_update("b", "three"); + +print md5_hash_finish("a"); +print md5_hash_finish("b"); diff --git a/testing/btest/bifs/sha1.test b/testing/btest/bifs/sha1.test new file mode 100644 index 0000000000..85c8df99c5 --- /dev/null +++ b/testing/btest/bifs/sha1.test @@ -0,0 +1,16 @@ +# @TEST-EXEC: bro -b %INPUT >output +# @TEST-EXEC: btest-diff output + +print sha1_hash("one"); +print sha1_hash("one", "two", "three"); + +sha1_hash_init("a"); +sha1_hash_init("b"); + +sha1_hash_update("a", "one"); +sha1_hash_update("b", "one"); +sha1_hash_update("b", "two"); +sha1_hash_update("b", "three"); + +print sha1_hash_finish("a"); +print sha1_hash_finish("b"); diff --git a/testing/btest/bifs/sha256.test b/testing/btest/bifs/sha256.test new file mode 100644 index 0000000000..7451f2fad3 --- /dev/null +++ b/testing/btest/bifs/sha256.test @@ -0,0 +1,16 @@ +# @TEST-EXEC: bro -b %INPUT >output +# @TEST-EXEC: btest-diff output + +print sha256_hash("one"); +print sha256_hash("one", "two", "three"); + +sha256_hash_init("a"); +sha256_hash_init("b"); + +sha256_hash_update("a", "one"); +sha256_hash_update("b", "one"); +sha256_hash_update("b", "two"); +sha256_hash_update("b", "three"); + +print sha256_hash_finish("a"); +print sha256_hash_finish("b");