From e5a589dbfe5fc4392543ac3ee1e1fb1da74380d5 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Mon, 16 Sep 2013 09:14:36 -0700 Subject: [PATCH 001/254] Very basic file-analyzer for x509 certificates. Mostly ripped from the ssl-analyzer and the topic/bernhard/x509 branch. Simply prints information about the encountered certificates (I have not yet my mind up, what I will log...). Next step: extensions... --- scripts/base/files/x509/__load__.bro | 1 + scripts/base/files/x509/main.bro | 14 + scripts/base/init-bare.bro | 20 ++ scripts/base/init-default.bro | 2 +- scripts/base/protocols/ssl/__load__.bro | 1 + scripts/base/protocols/ssl/files.bro | 48 +++ src/analyzer/protocol/ssl/ssl-analyzer.pac | 8 + src/file_analysis/analyzer/CMakeLists.txt | 1 + .../analyzer/x509/CMakeLists.txt | 10 + src/file_analysis/analyzer/x509/Plugin.cc | 10 + src/file_analysis/analyzer/x509/X509.cc | 295 ++++++++++++++++++ src/file_analysis/analyzer/x509/X509.h | 38 +++ src/file_analysis/analyzer/x509/events.bif | 1 + src/file_analysis/analyzer/x509/types.bif | 1 + 14 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 scripts/base/files/x509/__load__.bro create mode 100644 scripts/base/files/x509/main.bro create mode 100644 scripts/base/protocols/ssl/files.bro create mode 100644 src/file_analysis/analyzer/x509/CMakeLists.txt create mode 100644 src/file_analysis/analyzer/x509/Plugin.cc create mode 100644 src/file_analysis/analyzer/x509/X509.cc create mode 100644 src/file_analysis/analyzer/x509/X509.h create mode 100644 src/file_analysis/analyzer/x509/events.bif create mode 100644 src/file_analysis/analyzer/x509/types.bif diff --git a/scripts/base/files/x509/__load__.bro b/scripts/base/files/x509/__load__.bro new file mode 100644 index 0000000000..a10fe855df --- /dev/null +++ b/scripts/base/files/x509/__load__.bro @@ -0,0 +1 @@ +@load ./main diff --git a/scripts/base/files/x509/main.bro b/scripts/base/files/x509/main.bro new file mode 100644 index 0000000000..205b8fbd25 --- /dev/null +++ b/scripts/base/files/x509/main.bro @@ -0,0 +1,14 @@ + +@load base/frameworks/files + +module X509; + +export { + redef enum Log::ID += { LOG }; +} + +event x509_cert(f: fa_file, cert: X509::Certificate) + { + print cert; + } + diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index fe3b84a93b..5d7914dc6b 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2721,6 +2721,26 @@ export { }; } +module X509; +export { + type X509::Certificate: record { + version: count; ##< Version number. + serial: string; ##< Serial number. + subject: string; ##< Subject. + issuer: string; ##< Issuer. + not_valid_before: time; ##< Timestamp before when certificate is not valid. + not_valid_after: time; ##< Timestamp after when certificate is not valid. + key_alg: string; ##< name of the key algorithm + sig_alg: string; ##< name of the signature algorithm + key_type: string &optional; ##< key-type, if key parseable by openssl (either rsa, dsa or ec) + key_length: count &optional; ##< key-length in bits + exponent: string &optional; ##< exponent, if RSA-certificate + curve: string &optional; ##< curve, if EC-certificate + ca: bool &optional; ##< indicates the CA value in the X509v3 BasicConstraints extension + path_len: count &optional; ##< indicates the path_length value in the X509v3 BasicConstraints extension + }; +} + module SOCKS; export { ## This record is for a SOCKS client or server to provide either a diff --git a/scripts/base/init-default.bro b/scripts/base/init-default.bro index 202f8eaaab..c0fb29f081 100644 --- a/scripts/base/init-default.bro +++ b/scripts/base/init-default.bro @@ -57,6 +57,6 @@ @load base/files/hash @load base/files/extract @load base/files/unified2 - +@load base/files/x509 @load base/misc/find-checksum-offloading diff --git a/scripts/base/protocols/ssl/__load__.bro b/scripts/base/protocols/ssl/__load__.bro index 5a8590f234..42287fb039 100644 --- a/scripts/base/protocols/ssl/__load__.bro +++ b/scripts/base/protocols/ssl/__load__.bro @@ -1,5 +1,6 @@ @load ./consts @load ./main @load ./mozilla-ca-list +@load ./files @load-sigs ./dpd.sig diff --git a/scripts/base/protocols/ssl/files.bro b/scripts/base/protocols/ssl/files.bro new file mode 100644 index 0000000000..7582a428ae --- /dev/null +++ b/scripts/base/protocols/ssl/files.bro @@ -0,0 +1,48 @@ +@load ./main +@load base/utils/conn-ids +@load base/frameworks/files + +module SSL; + +export { + redef record Info += { + ## An ordered vector of file unique IDs which contains + ## all the certificates sent over the connection + fuids: vector of string &log &default=string_vec(); + }; + + ## Default file handle provider for SSL. + global get_file_handle: function(c: connection, is_orig: bool): string; + + ## Default file describer for SSL. + global describe_file: function(f: fa_file): string; +} + +function get_file_handle(c: connection, is_orig: bool): string + { + return cat(Analyzer::ANALYZER_SMTP, c$start_time); + } + +function describe_file(f: fa_file): string + { + # This shouldn't be needed, but just in case... + if ( f$source != "SSL" ) + return ""; + + return ""; + } + +event bro_init() &priority=5 + { + Files::register_protocol(Analyzer::ANALYZER_SSL, + [$get_file_handle = SSL::get_file_handle, + $describe = SSL::describe_file]); + } + +event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5 + { + if ( c?$ssl ) + c$ssl$fuids[|c$ssl$fuids|] = f$id; + + Files::add_analyzer(f, Files::ANALYZER_X509); + } diff --git a/src/analyzer/protocol/ssl/ssl-analyzer.pac b/src/analyzer/protocol/ssl/ssl-analyzer.pac index 3d9564eaab..4cd7599ef7 100644 --- a/src/analyzer/protocol/ssl/ssl-analyzer.pac +++ b/src/analyzer/protocol/ssl/ssl-analyzer.pac @@ -10,6 +10,8 @@ #include #include + +#include "file_analysis/Manager.h" %} @@ -253,6 +255,11 @@ refine connection SSL_Conn += { { const bytestring& cert = (*certificates)[i]; const uint8* data = cert.data(); + + file_mgr->DataIn(reinterpret_cast(data), cert.length(), + bro_analyzer()->GetAnalyzerTag(), bro_analyzer()->Conn(), false); + file_mgr->EndOfFile(bro_analyzer()->GetAnalyzerTag(), bro_analyzer()->Conn()); + X509* pTemp = d2i_X509_binpac(NULL, &data, cert.length()); if ( ! pTemp ) { @@ -261,6 +268,7 @@ refine connection SSL_Conn += { return false; } + RecordVal* pX509Cert = new RecordVal(x509_type); char tmp[256]; BIO *bio = BIO_new(BIO_s_mem()); diff --git a/src/file_analysis/analyzer/CMakeLists.txt b/src/file_analysis/analyzer/CMakeLists.txt index 1e19b7bd11..ede63dbd1b 100644 --- a/src/file_analysis/analyzer/CMakeLists.txt +++ b/src/file_analysis/analyzer/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(data_event) add_subdirectory(extract) add_subdirectory(hash) add_subdirectory(unified2) +add_subdirectory(x509) diff --git a/src/file_analysis/analyzer/x509/CMakeLists.txt b/src/file_analysis/analyzer/x509/CMakeLists.txt new file mode 100644 index 0000000000..759a01b55c --- /dev/null +++ b/src/file_analysis/analyzer/x509/CMakeLists.txt @@ -0,0 +1,10 @@ + +include(BroPlugin) + +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}) + +bro_plugin_begin(Bro X509) +bro_plugin_cc(X509.cc Plugin.cc ../../Analyzer.cc) +bro_plugin_bif(events.bif types.bif) +bro_plugin_end() diff --git a/src/file_analysis/analyzer/x509/Plugin.cc b/src/file_analysis/analyzer/x509/Plugin.cc new file mode 100644 index 0000000000..1e76e3fdb7 --- /dev/null +++ b/src/file_analysis/analyzer/x509/Plugin.cc @@ -0,0 +1,10 @@ +#include "plugin/Plugin.h" + +#include "X509.h" + +BRO_PLUGIN_BEGIN(Bro, X509) + BRO_PLUGIN_DESCRIPTION("Parse X509 Certificate"); + BRO_PLUGIN_FILE_ANALYZER("X509", X509); + BRO_PLUGIN_BIF_FILE(events); + BRO_PLUGIN_BIF_FILE(types); +BRO_PLUGIN_END diff --git a/src/file_analysis/analyzer/x509/X509.cc b/src/file_analysis/analyzer/x509/X509.cc new file mode 100644 index 0000000000..78d746ac9b --- /dev/null +++ b/src/file_analysis/analyzer/x509/X509.cc @@ -0,0 +1,295 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include + +#include "X509.h" +#include "Event.h" + +#include "events.bif.h" +#include "types.bif.h" + +#include "file_analysis/Manager.h" + +#include +#include +#include +#include + +using namespace file_analysis; + +file_analysis::X509::X509(RecordVal* args, file_analysis::File* file) + : file_analysis::Analyzer(file_mgr->GetComponentTag("X509"), args, file) + { + cert_data.clear(); + } + +bool file_analysis::X509::DeliverStream(const u_char* data, uint64 len) + { + // just add it to the data we have so far, since we cannot do anything else anyways... + cert_data.append(reinterpret_cast(data), len); + return true; + } + +bool file_analysis::X509::Undelivered(uint64 offset, uint64 len) + { + return false; + } + +bool file_analysis::X509::EndOfFile() + { + // ok, now we can try to parse the certificate with openssl. Should + // be rather straightforward... + const unsigned char* cert_char = reinterpret_cast(cert_data.data()); + ::X509* ssl_cert = d2i_X509(NULL, &cert_char, cert_data.size()); + if ( !ssl_cert ) + { + reporter->Error("Could not parse X509 certificate"); + return false; + } + + char buf[256]; // we need a buffer for some of the openssl functions + memset(buf, 0, 256); + + RecordVal* pX509Cert = new RecordVal(BifType::Record::X509::Certificate); + BIO *bio = BIO_new(BIO_s_mem()); + + pX509Cert->Assign(0, new Val((uint64) X509_get_version(ssl_cert), TYPE_COUNT)); + i2a_ASN1_INTEGER(bio, X509_get_serialNumber(ssl_cert)); + int len = BIO_read(bio, &(*buf), sizeof buf); + pX509Cert->Assign(1, new StringVal(len, buf)); + + X509_NAME_print_ex(bio, X509_get_subject_name(ssl_cert), 0, XN_FLAG_RFC2253); + len = BIO_gets(bio, &(*buf), sizeof buf); + pX509Cert->Assign(2, new StringVal(len, buf)); + X509_NAME_print_ex(bio, X509_get_issuer_name(ssl_cert), 0, XN_FLAG_RFC2253); + len = BIO_gets(bio, &(*buf), sizeof buf); + pX509Cert->Assign(3, new StringVal(len, buf)); + BIO_free(bio); + + pX509Cert->Assign(4, new Val(get_time_from_asn1(X509_get_notBefore(ssl_cert)), TYPE_TIME)); + pX509Cert->Assign(5, new Val(get_time_from_asn1(X509_get_notAfter(ssl_cert)), TYPE_TIME)); + + // we only read 255 bytes because byte 256 is always 0. + // if the string is longer than 255, that will be our null-termination, + // otherwhise i2t does null-terminate. + if ( ! i2t_ASN1_OBJECT(buf, 255, ssl_cert->cert_info->key->algor->algorithm) ) + buf[0] = 0; + pX509Cert->Assign(6, new StringVal(buf)); + + if ( ! i2t_ASN1_OBJECT(buf, 255, ssl_cert->sig_alg->algorithm) ) + buf[0] = 0; + pX509Cert->Assign(7, new StringVal(buf)); + + // Things we can do when we have the key... + EVP_PKEY *pkey = X509_extract_key(ssl_cert); + if ( pkey != NULL ) + { + if ( pkey->type == EVP_PKEY_DSA ) + { + pX509Cert->Assign(8, new StringVal("dsa")); + } + else if ( pkey->type == EVP_PKEY_RSA ) + { + pX509Cert->Assign(8, new StringVal("rsa")); + char *exponent = BN_bn2dec(pkey->pkey.rsa->e); + if ( exponent != NULL ) + { + pX509Cert->Assign(10, new StringVal(exponent)); + OPENSSL_free(exponent); + exponent = NULL; + } + } +#ifndef OPENSSL_NO_EC + else if ( pkey->type == EVP_PKEY_EC ) + { + pX509Cert->Assign(8, new StringVal("dsa")); + pX509Cert->Assign(11, key_curve(pkey)); + } +#endif + + unsigned int length = key_length(pkey); + if ( length > 0 ) + pX509Cert->Assign(9, new Val(length, TYPE_COUNT)); + } + + val_list* vl = new val_list(); + vl->append(GetFile()->GetVal()->Ref()); + vl->append(pX509Cert); + + mgr.QueueEvent(x509_cert, vl); + + return false; + } + +StringVal* file_analysis::X509::key_curve(EVP_PKEY *key) + { + assert(key != NULL); + +#ifdef OPENSSL_NO_EC + // well, we do not have EC-Support... + return NULL; +#else + if ( key->type != EVP_PKEY_EC ) { + // no EC-key - no curve name + return NULL; + } + + const EC_GROUP *group; + int nid; + if ( (group = EC_KEY_get0_group(key->pkey.ec)) == NULL) + // I guess we could not parse this + return NULL; + + nid = EC_GROUP_get_curve_name(group); + if ( nid == 0 ) + // and an invalid nid... + return NULL; + + const char * curve_name = OBJ_nid2sn(nid); + if ( curve_name == NULL ) + return NULL; + + return new StringVal(curve_name); +#endif + } + +unsigned int file_analysis::X509::key_length(EVP_PKEY *key) + { + assert(key != NULL); + unsigned int length; + + switch(key->type) { + case EVP_PKEY_RSA: + length = BN_num_bits(key->pkey.rsa->n); + break; + case EVP_PKEY_DSA: + length = BN_num_bits(key->pkey.dsa->p); + break; +#ifndef OPENSSL_NO_EC + case EVP_PKEY_EC: + { + const EC_GROUP *group; + BIGNUM* ec_order; + ec_order = BN_new(); + if ( !ec_order ) + // could not malloc bignum? + return 0; + + if ( (group = EC_KEY_get0_group(key->pkey.ec)) == NULL) + // unknown ex-group + return 0; + + if (!EC_GROUP_get_order(group, ec_order, NULL)) + // could not get ec-group-order + return 0; + + length = BN_num_bits(ec_order); + BN_free(ec_order); + break; + } +#endif + default: + return 0; // unknown public key type + } + + return length; + } + +double file_analysis::X509::get_time_from_asn1(const ASN1_TIME * atime) + { + time_t lResult = 0; + + char lBuffer[24]; + char * pBuffer = lBuffer; + + size_t lTimeLength = atime->length; + char * pString = (char *) atime->data; + + if ( atime->type == V_ASN1_UTCTIME ) + { + if ( lTimeLength < 11 || lTimeLength > 17 ) + return 0; + + memcpy(pBuffer, pString, 10); + pBuffer += 10; + pString += 10; + } + else + { + if ( lTimeLength < 13 ) + return 0; + + memcpy(pBuffer, pString, 12); + pBuffer += 12; + pString += 12; + } + + if ((*pString == 'Z') || (*pString == '-') || (*pString == '+')) + { + *(pBuffer++) = '0'; + *(pBuffer++) = '0'; + } + else + { + *(pBuffer++) = *(pString++); + *(pBuffer++) = *(pString++); + + // Skip any fractional seconds... + if (*pString == '.') + { + pString++; + while ((*pString >= '0') && (*pString <= '9')) + pString++; + } + } + + *(pBuffer++) = 'Z'; + *(pBuffer++) = '\0'; + + time_t lSecondsFromUTC; + + if ( *pString == 'Z' ) + lSecondsFromUTC = 0; + + else + { + if ((*pString != '+') && (pString[5] != '-')) + return 0; + + lSecondsFromUTC = ((pString[1]-'0') * 10 + (pString[2]-'0')) * 60; + lSecondsFromUTC += (pString[3]-'0') * 10 + (pString[4]-'0'); + + if (*pString == '-') + lSecondsFromUTC = -lSecondsFromUTC; + } + + tm lTime; + lTime.tm_sec = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0'); + lTime.tm_min = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0'); + lTime.tm_hour = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0'); + lTime.tm_mday = ((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0'); + lTime.tm_mon = (((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0')) - 1; + lTime.tm_year = ((lBuffer[0] - '0') * 10) + (lBuffer[1] - '0'); + + if ( lTime.tm_year < 50 ) + lTime.tm_year += 100; // RFC 2459 + + lTime.tm_wday = 0; + lTime.tm_yday = 0; + lTime.tm_isdst = 0; // No DST adjustment requested + + lResult = mktime(&lTime); + + if ( lResult ) + { + if ( 0 != lTime.tm_isdst ) + lResult -= 3600; // mktime may adjust for DST (OS dependent) + + lResult += lSecondsFromUTC; + } + else + lResult = 0; + + return lResult; +} + diff --git a/src/file_analysis/analyzer/x509/X509.h b/src/file_analysis/analyzer/x509/X509.h new file mode 100644 index 0000000000..ce74190b69 --- /dev/null +++ b/src/file_analysis/analyzer/x509/X509.h @@ -0,0 +1,38 @@ +#ifndef FILE_ANALYSIS_X509_H +#define FILE_ANALYSIS_X509_H + +#include + +#include "Val.h" +#include "../File.h" +#include "Analyzer.h" + +#include + +namespace file_analysis { + +class X509 : public file_analysis::Analyzer { +public: + //~X509(); + + static file_analysis::Analyzer* Instantiate(RecordVal* args, File* file) + { return new X509(args, file); } + + virtual bool DeliverStream(const u_char* data, uint64 len); + virtual bool Undelivered(uint64 offset, uint64 len); + virtual bool EndOfFile(); + +protected: + X509(RecordVal* args, File* file); + +private: + static double get_time_from_asn1(const ASN1_TIME * atime); + static StringVal* key_curve(EVP_PKEY *key); + static unsigned int key_length(EVP_PKEY *key); + + std::string cert_data; +}; + +} + +#endif diff --git a/src/file_analysis/analyzer/x509/events.bif b/src/file_analysis/analyzer/x509/events.bif new file mode 100644 index 0000000000..3c3049559d --- /dev/null +++ b/src/file_analysis/analyzer/x509/events.bif @@ -0,0 +1 @@ +event x509_cert%(f: fa_file, cert: X509::Certificate%); diff --git a/src/file_analysis/analyzer/x509/types.bif b/src/file_analysis/analyzer/x509/types.bif new file mode 100644 index 0000000000..9e4fd48420 --- /dev/null +++ b/src/file_analysis/analyzer/x509/types.bif @@ -0,0 +1 @@ +type X509::Certificate: record; From df552ca87d842ca66a9bd234f0feea2ac8174929 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Thu, 19 Sep 2013 14:35:11 -0700 Subject: [PATCH 002/254] parse out extension. One event for general extensions (just returns the openssl-parsed string-value), one event for basicconstraints (is a certificate a CA or not) and one event for subject-alternative-names (only DNS parts). --- scripts/base/files/x509/main.bro | 15 ++ scripts/base/init-bare.bro | 22 ++- src/analyzer/protocol/ssl/SSL.h | 2 +- src/analyzer/protocol/ssl/events.bif | 2 +- src/analyzer/protocol/ssl/ssl-analyzer.pac | 28 ---- src/file_analysis/analyzer/x509/X509.cc | 153 ++++++++++++++++++++- src/file_analysis/analyzer/x509/X509.h | 6 + src/file_analysis/analyzer/x509/events.bif | 3 + src/file_analysis/analyzer/x509/types.bif | 4 + 9 files changed, 202 insertions(+), 33 deletions(-) diff --git a/scripts/base/files/x509/main.bro b/scripts/base/files/x509/main.bro index 205b8fbd25..458a389934 100644 --- a/scripts/base/files/x509/main.bro +++ b/scripts/base/files/x509/main.bro @@ -12,3 +12,18 @@ event x509_cert(f: fa_file, cert: X509::Certificate) print cert; } +event x509_extension(f: fa_file, ext: X509::Extension) +{ +print ext; +} + +event x509_ext_basic_constraints(f: fa_file, ext: X509::BasicConstraints) +{ +print ext; +} + +event x509_ext_subject_alternative_name(f: fa_file, ext: X509::SubjectAlternativeName) +{ +print ext; +} + diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 5d7914dc6b..c8e2e52b8a 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2736,9 +2736,27 @@ export { key_length: count &optional; ##< key-length in bits exponent: string &optional; ##< exponent, if RSA-certificate curve: string &optional; ##< curve, if EC-certificate - ca: bool &optional; ##< indicates the CA value in the X509v3 BasicConstraints extension - path_len: count &optional; ##< indicates the path_length value in the X509v3 BasicConstraints extension + #ca: bool &optional; ##< indicates the CA value in the X509v3 BasicConstraints extension + #path_len: count &optional; ##< indicates the path_length value in the X509v3 BasicConstraints extension }; + + type X509::Extension: record { + name: string; ##< long name of extension. oid if name not known + short_name: string &optional; ##< short name of extension if known. + oid: string; ##< oid of extension + critical: bool; ##< true if extension is critical + value: string; ##< extension content parsed to string for known extensions. Raw data otherwise. + }; + + type X509::BasicConstraints: record { + ca: bool; ##< CA flag set? + path_len: count &optional; + }; + + type X509::SubjectAlternativeName: record { + names: vector of string; + }; + } module SOCKS; diff --git a/src/analyzer/protocol/ssl/SSL.h b/src/analyzer/protocol/ssl/SSL.h index 6423d1b155..5749066780 100644 --- a/src/analyzer/protocol/ssl/SSL.h +++ b/src/analyzer/protocol/ssl/SSL.h @@ -28,7 +28,7 @@ public: { return ( ssl_client_hello || ssl_server_hello || ssl_established || ssl_extension || ssl_alert || - x509_certificate || x509_extension || x509_error ); + x509_certificate || x509_error ); } protected: diff --git a/src/analyzer/protocol/ssl/events.bif b/src/analyzer/protocol/ssl/events.bif index 3d0c7e9d6a..b7586561fc 100644 --- a/src/analyzer/protocol/ssl/events.bif +++ b/src/analyzer/protocol/ssl/events.bif @@ -176,7 +176,7 @@ event x509_certificate%(c: connection, is_orig: bool, cert: X509, chain_idx: cou ## ## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension ## ssl_server_hello x509_certificate x509_error x509_verify -event x509_extension%(c: connection, is_orig: bool, data: string%); +#event x509_extension%(c: connection, is_orig: bool, data: string%); ## Generated when errors occur during parsing an X509 certificate. ## diff --git a/src/analyzer/protocol/ssl/ssl-analyzer.pac b/src/analyzer/protocol/ssl/ssl-analyzer.pac index 4cd7599ef7..43e2ac5c73 100644 --- a/src/analyzer/protocol/ssl/ssl-analyzer.pac +++ b/src/analyzer/protocol/ssl/ssl-analyzer.pac @@ -296,34 +296,6 @@ refine connection SSL_Conn += { i, certificates->size(), der_cert); - // Are there any X509 extensions? - //printf("Number of x509 extensions: %d\n", X509_get_ext_count(pTemp)); - if ( x509_extension && X509_get_ext_count(pTemp) > 0 ) - { - int num_ext = X509_get_ext_count(pTemp); - for ( int k = 0; k < num_ext; ++k ) - { - unsigned char *pBuffer = 0; - int length = 0; - - X509_EXTENSION* ex = X509_get_ext(pTemp, k); - if (ex) - { - ASN1_STRING *pString = X509_EXTENSION_get_data(ex); - length = ASN1_STRING_to_UTF8(&pBuffer, pString); - //i2t_ASN1_OBJECT(&pBuffer, length, obj) - // printf("extension length: %d\n", length); - // -1 indicates an error. - if ( length >= 0 ) - { - StringVal* value = new StringVal(length, (char*)pBuffer); - BifEvent::generate_x509_extension(bro_analyzer(), - bro_analyzer()->Conn(), ${rec.is_orig}, value); - } - OPENSSL_free(pBuffer); - } - } - } X509_free(pTemp); } } diff --git a/src/file_analysis/analyzer/x509/X509.cc b/src/file_analysis/analyzer/x509/X509.cc index 78d746ac9b..3d7871be9a 100644 --- a/src/file_analysis/analyzer/x509/X509.cc +++ b/src/file_analysis/analyzer/x509/X509.cc @@ -47,6 +47,27 @@ bool file_analysis::X509::EndOfFile() return false; } + ParseCertificate(ssl_cert); + + // after parsing the certificate - parse the extensions... + + int num_ext = X509_get_ext_count(ssl_cert); + for ( int k = 0; k < num_ext; ++k ) + { + X509_EXTENSION* ex = X509_get_ext(ssl_cert, k); + if ( !ex ) + continue; + + ParseExtension(ex); + } + + X509_free(ssl_cert); + + return false; + } + +void file_analysis::X509::ParseCertificate(::X509* ssl_cert) + { char buf[256]; // we need a buffer for some of the openssl functions memset(buf, 0, 256); @@ -117,8 +138,138 @@ bool file_analysis::X509::EndOfFile() vl->append(pX509Cert); mgr.QueueEvent(x509_cert, vl); + } + +void file_analysis::X509::ParseExtension(X509_EXTENSION* ex) + { + char name[256]; + char oid[256]; + + ASN1_OBJECT* ext_asn = X509_EXTENSION_get_object(ex); + const char* short_name = OBJ_nid2sn(OBJ_obj2nid(ext_asn)); + + OBJ_obj2txt(name, 255, ext_asn, 0); + OBJ_obj2txt(oid, 255, ext_asn, 1); + + int critical = 0; + if ( X509_EXTENSION_get_critical(ex) != 0 ) + critical = 1; + + BIO *bio = BIO_new(BIO_s_mem()); + if(!X509V3_EXT_print(bio, ex, 0, 0)) + M_ASN1_OCTET_STRING_print(bio,ex->value); - return false; + BIO_flush(bio); + int length = BIO_pending(bio); + char *buffer = new char[length]; + BIO_read(bio, (void*)buffer, length); + StringVal* ext_val = new StringVal(length, buffer); + delete(buffer); + BIO_free_all(bio); + + RecordVal* pX509Ext = new RecordVal(BifType::Record::X509::Extension); + pX509Ext->Assign(0, new StringVal(name)); + if ( short_name and strlen(short_name) > 0 ) + pX509Ext->Assign(1, new StringVal(short_name)); + pX509Ext->Assign(2, new StringVal(oid)); + pX509Ext->Assign(3, new Val(critical, TYPE_BOOL)); + pX509Ext->Assign(4, ext_val); + + // send off generic extension event + // + // and then look if we have a specialized event for the extension we just + // parsed. And if we have it, we send the specialized event on top of the + // generic event that we just had. I know, that is... kind of not nice, + // but I am not sure if there is a better way to do it... + val_list* vl = new val_list(); + vl->append(GetFile()->GetVal()->Ref()); + vl->append(pX509Ext); + + mgr.QueueEvent(x509_extension, vl); + + + // look if we have a specialized handler for this event... + if ( OBJ_obj2nid(ext_asn) == NID_basic_constraints ) + ParseBasicConstraints(ex); + else if ( OBJ_obj2nid(ext_asn) == NID_subject_alt_name ) + ParseSAN(ex); + + + + } +void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex) + { + assert(OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == NID_basic_constraints); + + RecordVal* pBasicConstraint = new RecordVal(BifType::Record::X509::BasicConstraints); + BASIC_CONSTRAINTS *constr = (BASIC_CONSTRAINTS *) X509V3_EXT_d2i(ex); + if ( !constr ) + { + reporter->Error("Certificate with invalid BasicConstraint"); + } + else + { + pBasicConstraint->Assign(0, new Val(constr->ca ? 1 : 0, TYPE_BOOL)); + if ( constr->pathlen ) { + pBasicConstraint->Assign(1, new Val((int32_t) ASN1_INTEGER_get(constr->pathlen), TYPE_COUNT)); + } + val_list* vl = new val_list(); + vl->append(GetFile()->GetVal()->Ref()); + vl->append(pBasicConstraint); + + mgr.QueueEvent(x509_ext_basic_constraints, vl); + + } + + } + +void file_analysis::X509::ParseSAN(X509_EXTENSION* ext) + { + assert(OBJ_obj2nid(X509_EXTENSION_get_object(ext)) == NID_subject_alt_name); + + GENERAL_NAMES *altname = (GENERAL_NAMES*)X509V3_EXT_d2i(ext); + if ( !altname ) + { + reporter->Error("could not parse subject alternative names"); + return; + } + + VectorVal* names = new VectorVal(internal_type("string_vec")->AsVectorType()); + + int j = 0; + for ( int i = 0; i < sk_GENERAL_NAME_num(altname); i++ ) + { + GENERAL_NAME *gen = sk_GENERAL_NAME_value(altname, i); + assert(gen); + + if ( gen->type == GEN_DNS ) + { + if (ASN1_STRING_type(gen->d.ia5) != V_ASN1_IA5STRING) + { + reporter->Error("DNS-field does not contain an IA5String"); + continue; + } + const char* name = (const char*) ASN1_STRING_data(gen->d.ia5); + StringVal* bs = new StringVal(name); + names->Assign(j, bs); + j++; + } + else + { + // we should perhaps sometime parse out ip-addresses + reporter->Error("Subject alternative name contained non-dns fields"); + continue; + } + } + + RecordVal* pSan = new RecordVal(BifType::Record::X509::SubjectAlternativeName); + pSan->Assign(0, names); + + val_list* vl = new val_list(); + vl->append(GetFile()->GetVal()->Ref()); + vl->append(pSan); + + mgr.QueueEvent(x509_ext_basic_constraints, vl); } StringVal* file_analysis::X509::key_curve(EVP_PKEY *key) diff --git a/src/file_analysis/analyzer/x509/X509.h b/src/file_analysis/analyzer/x509/X509.h index ce74190b69..cc0131afac 100644 --- a/src/file_analysis/analyzer/x509/X509.h +++ b/src/file_analysis/analyzer/x509/X509.h @@ -7,6 +7,7 @@ #include "../File.h" #include "Analyzer.h" +#include #include namespace file_analysis { @@ -30,6 +31,11 @@ private: static StringVal* key_curve(EVP_PKEY *key); static unsigned int key_length(EVP_PKEY *key); + void ParseCertificate(::X509* ssl_cert); + void ParseExtension(X509_EXTENSION* ex); + void ParseBasicConstraints(X509_EXTENSION* ex); + void ParseSAN(X509_EXTENSION* ex); + std::string cert_data; }; diff --git a/src/file_analysis/analyzer/x509/events.bif b/src/file_analysis/analyzer/x509/events.bif index 3c3049559d..148d09ec00 100644 --- a/src/file_analysis/analyzer/x509/events.bif +++ b/src/file_analysis/analyzer/x509/events.bif @@ -1 +1,4 @@ event x509_cert%(f: fa_file, cert: X509::Certificate%); +event x509_extension%(f: fa_file, ext: X509::Extension%); +event x509_ext_basic_constraints%(f: fa_file, ext: X509::BasicConstraints%); +event x509_ext_subject_alternative_name%(f: fa_file, ext: X509::SubjectAlternativeName%); diff --git a/src/file_analysis/analyzer/x509/types.bif b/src/file_analysis/analyzer/x509/types.bif index 9e4fd48420..49a915c7fc 100644 --- a/src/file_analysis/analyzer/x509/types.bif +++ b/src/file_analysis/analyzer/x509/types.bif @@ -1 +1,5 @@ type X509::Certificate: record; +type X509::Extension: record; +type X509::BasicConstraints: record; +type X509::SubjectAlternativeName: record; + From 2b87499fd96ea28cf66f999ffd97b94f5596a7b2 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Tue, 1 Oct 2013 16:20:55 -0700 Subject: [PATCH 003/254] rip out x509 code from ssl analyzer. Note that since at the moment the file analyzer does not yet re-populate the info record that means quite a lot of information is simply not available. --- scripts/base/protocols/ssl/main.bro | 43 ------- src/analyzer/protocol/ssl/CMakeLists.txt | 1 - src/analyzer/protocol/ssl/Plugin.cc | 1 - src/analyzer/protocol/ssl/SSL.h | 3 +- src/analyzer/protocol/ssl/events.bif | 73 +----------- src/analyzer/protocol/ssl/functions.bif | 132 --------------------- src/analyzer/protocol/ssl/ssl-analyzer.pac | 57 +-------- 7 files changed, 12 insertions(+), 298 deletions(-) delete mode 100644 src/analyzer/protocol/ssl/functions.bif diff --git a/scripts/base/protocols/ssl/main.bro b/scripts/base/protocols/ssl/main.bro index 2381b356e4..1b487ef4bf 100644 --- a/scripts/base/protocols/ssl/main.bro +++ b/scripts/base/protocols/ssl/main.bro @@ -168,49 +168,6 @@ event ssl_server_hello(c: connection, version: count, possible_ts: time, session c$ssl$cipher = cipher_desc[cipher]; } -event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) &priority=5 - { - set_session(c); - - # We aren't doing anything with client certificates yet. - if ( is_orig ) - { - if ( chain_idx == 0 ) - { - # Save the primary cert. - c$ssl$client_cert = der_cert; - - # Also save other certificate information about the primary cert. - c$ssl$client_subject = cert$subject; - c$ssl$client_issuer_subject = cert$issuer; - } - else - { - # Otherwise, add it to the cert validation chain. - c$ssl$client_cert_chain[|c$ssl$client_cert_chain|] = der_cert; - } - } - else - { - if ( chain_idx == 0 ) - { - # Save the primary cert. - c$ssl$cert = der_cert; - - # 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; - } - else - { - # Otherwise, add it to the cert validation chain. - c$ssl$cert_chain[|c$ssl$cert_chain|] = der_cert; - } - } - } - event ssl_extension(c: connection, is_orig: bool, code: count, val: string) &priority=5 { set_session(c); diff --git a/src/analyzer/protocol/ssl/CMakeLists.txt b/src/analyzer/protocol/ssl/CMakeLists.txt index f1838e5f3b..2591c5dfec 100644 --- a/src/analyzer/protocol/ssl/CMakeLists.txt +++ b/src/analyzer/protocol/ssl/CMakeLists.txt @@ -6,6 +6,5 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI bro_plugin_begin(Bro SSL) bro_plugin_cc(SSL.cc Plugin.cc) bro_plugin_bif(events.bif) -bro_plugin_bif(functions.bif) bro_plugin_pac(ssl.pac ssl-analyzer.pac ssl-protocol.pac ssl-defs.pac) bro_plugin_end() diff --git a/src/analyzer/protocol/ssl/Plugin.cc b/src/analyzer/protocol/ssl/Plugin.cc index c63be864f8..c1783b357d 100644 --- a/src/analyzer/protocol/ssl/Plugin.cc +++ b/src/analyzer/protocol/ssl/Plugin.cc @@ -7,5 +7,4 @@ BRO_PLUGIN_BEGIN(Bro, SSL) BRO_PLUGIN_DESCRIPTION("SSL analyzer"); BRO_PLUGIN_ANALYZER("SSL", ssl::SSL_Analyzer); BRO_PLUGIN_BIF_FILE(events); - BRO_PLUGIN_BIF_FILE(functions); BRO_PLUGIN_END diff --git a/src/analyzer/protocol/ssl/SSL.h b/src/analyzer/protocol/ssl/SSL.h index 5749066780..f674d64fed 100644 --- a/src/analyzer/protocol/ssl/SSL.h +++ b/src/analyzer/protocol/ssl/SSL.h @@ -27,8 +27,7 @@ public: static bool Available() { return ( ssl_client_hello || ssl_server_hello || - ssl_established || ssl_extension || ssl_alert || - x509_certificate || x509_error ); + ssl_established || ssl_extension || ssl_alert ); } protected: diff --git a/src/analyzer/protocol/ssl/events.bif b/src/analyzer/protocol/ssl/events.bif index b7586561fc..aff5f4798c 100644 --- a/src/analyzer/protocol/ssl/events.bif +++ b/src/analyzer/protocol/ssl/events.bif @@ -22,7 +22,7 @@ ## :bro:id:`SSL::cipher_desc` table maps them to descriptive names. ## ## .. bro:see:: ssl_alert ssl_established ssl_extension ssl_server_hello -## ssl_session_ticket_handshake x509_certificate x509_error x509_extension +## ssl_session_ticket_handshake event ssl_client_hello%(c: connection, version: count, possible_ts: time, session_id: string, ciphers: count_set%); ## Generated for an SSL/TLS server's initial *hello* message. SSL/TLS sessions @@ -52,7 +52,7 @@ event ssl_client_hello%(c: connection, version: count, possible_ts: time, sessio ## standardized as part of the SSL/TLS protocol. ## ## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension -## ssl_session_ticket_handshake x509_certificate x509_error x509_extension +## ssl_session_ticket_handshake event ssl_server_hello%(c: connection, version: count, possible_ts: time, session_id: string, cipher: count, comp_method: count%); ## Generated for SSL/TLS extensions seen in an initial handshake. SSL/TLS @@ -71,7 +71,7 @@ event ssl_server_hello%(c: connection, version: count, possible_ts: time, sessio ## val: The raw extension value that was sent in the message. ## ## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_server_hello -## ssl_session_ticket_handshake x509_certificate x509_error x509_extension +## ssl_session_ticket_handshake event ssl_extension%(c: connection, is_orig: bool, code: count, val: string%); ## Generated at the end of an SSL/TLS handshake. SSL/TLS sessions start with @@ -86,7 +86,7 @@ event ssl_extension%(c: connection, is_orig: bool, code: count, val: string%); ## c: The connection. ## ## .. bro:see:: ssl_alert ssl_client_hello ssl_extension ssl_server_hello -## ssl_session_ticket_handshake x509_certificate x509_error x509_extension +## ssl_session_ticket_handshake event ssl_established%(c: connection%); ## Generated for SSL/TLS alert records. SSL/TLS sessions start with an @@ -109,7 +109,7 @@ event ssl_established%(c: connection%); ## defined as part of the SSL/TLS protocol. ## ## .. bro:see:: ssl_client_hello ssl_established ssl_extension ssl_server_hello -## ssl_session_ticket_handshake x509_certificate x509_error x509_extension +## ssl_session_ticket_handshake event ssl_alert%(c: connection, is_orig: bool, level: count, desc: count%); ## Generated for SSL/TLS handshake messages that are a part of the @@ -130,66 +130,5 @@ event ssl_alert%(c: connection, is_orig: bool, level: count, desc: count%); ## ticket: The raw ticket data. ## ## .. bro:see:: ssl_client_hello ssl_established ssl_extension ssl_server_hello -## x509_certificate x509_error x509_extension ssl_alert +## ssl_alert event ssl_session_ticket_handshake%(c: connection, ticket_lifetime_hint: count, ticket: string%); - -## Generated for X509 certificates seen in SSL/TLS connections. During the -## initial SSL/TLS handshake, certificates are exchanged in the clear. Bro -## raises this event for each certificate seen (including both a site's primary -## cert, and further certs sent as part of the validation chain). -## -## See `Wikipedia `__ for more information -## about the X.509 format. -## -## c: The connection. -## -## is_orig: True if event is raised for originator side of the connection. -## -## cert: The parsed certificate. -## -## chain_idx: The index in the validation chain that this cert has. Index zero -## indicates an endpoint's primary cert, while higher indices -## indicate the place in the validation chain (which has length -## *chain_len*). -## -## chain_len: The total length of the validation chain that this cert is part -## of. -## -## der_cert: The complete cert encoded in `DER -## `__ -## format. -## -## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension -## ssl_server_hello x509_error x509_extension x509_verify -event x509_certificate%(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string%); - -## Generated for X509 extensions seen in a certificate. -## -## See `Wikipedia `__ for more information -## about the X.509 format. -## -## c: The connection. -## -## is_orig: True if event is raised for originator side of the connection. -## -## data: The raw data associated with the extension. -## -## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension -## ssl_server_hello x509_certificate x509_error x509_verify -#event x509_extension%(c: connection, is_orig: bool, data: string%); - -## Generated when errors occur during parsing an X509 certificate. -## -## See `Wikipedia `__ for more information -## about the X.509 format. -## -## c: The connection. -## -## is_orig: True if event is raised for originator side of the connection. -## -## err: An error code describing what went wrong. :bro:id:`SSL::x509_errors` -## maps error codes to a textual description. -## -## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension -## ssl_server_hello x509_certificate x509_extension x509_err2str x509_verify -event x509_error%(c: connection, is_orig: bool, err: count%); diff --git a/src/analyzer/protocol/ssl/functions.bif b/src/analyzer/protocol/ssl/functions.bif deleted file mode 100644 index f2d4861007..0000000000 --- a/src/analyzer/protocol/ssl/functions.bif +++ /dev/null @@ -1,132 +0,0 @@ - -%%{ -#include -#include -#include - -// This is the indexed map of X509 certificate stores. -static map x509_stores; - -// ### NOTE: while d2i_X509 does not take a const u_char** pointer, -// here we assume d2i_X509 does not write to , so it is safe to -// convert data to a non-const pointer. Could some X509 guru verify -// this? - -X509* d2i_X509_(X509** px, const u_char** in, int len) - { -#ifdef OPENSSL_D2I_X509_USES_CONST_CHAR - return d2i_X509(px, in, len); -#else - return d2i_X509(px, (u_char**)in, len); -#endif - } - -%%} - - -## Verifies a certificate. -## -## der_cert: The X.509 certificate in DER format. -## -## cert_stack: Specifies a certificate chain to validate against, with index 0 -## typically being the root CA. Bro uses the Mozilla root CA list -## by default. -## -## root_certs: A list of additional root certificates that extends -## *cert_stack*. -## -## Returns: A status code of the verification which can be converted into an -## ASCII string via :bro:id:`x509_err2str`. -## -## .. bro:see:: x509_err2str -function x509_verify%(der_cert: string, cert_stack: string_vec, root_certs: table_string_of_string%): count - %{ - X509_STORE* ctx = 0; - int i = 0; - - // If this certificate store was built previously, just reuse the old one. - if ( x509_stores.count(root_certs) > 0 ) - ctx = x509_stores[root_certs]; - - if ( ! ctx ) // lookup to see if we have this one built already! - { - ctx = X509_STORE_new(); - TableVal* root_certs2 = root_certs->AsTableVal(); - ListVal* idxs = root_certs2->ConvertToPureList(); - - // Build the validation store - for ( i = 0; i < idxs->Length(); ++i ) - { - Val* key = idxs->Index(i); - StringVal *sv = root_certs2->Lookup(key)->AsStringVal(); - const uint8* data = sv->Bytes(); - X509* x = d2i_X509_(NULL, &data, sv->Len()); - if ( ! x ) - { - builtin_error(fmt("Root CA error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); - return new Val((uint64) ERR_get_error(), TYPE_COUNT); - } - X509_STORE_add_cert(ctx, x); - } - delete idxs; - - // Save the newly constructed certificate store into the cacheing map. - x509_stores[root_certs] = ctx; - } - - const uint8 *cert_data = der_cert->Bytes(); - X509* cert = d2i_X509_(NULL, &cert_data, der_cert->Len()); - if ( ! cert ) - { - builtin_error(fmt("Certificate error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); - return new Val((uint64) ERR_get_error(), TYPE_COUNT); - } - - STACK_OF(X509)* untrusted_certs = sk_X509_new_null(); - if ( ! untrusted_certs ) - { - builtin_error(fmt("Untrusted certificate stack initialization error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); - return new Val((uint64) ERR_get_error(), TYPE_COUNT); - } - - VectorVal *cert_stack_vec = cert_stack->AsVectorVal(); - for ( i = 0; i < (int) cert_stack_vec->Size(); ++i ) - { - StringVal *sv = cert_stack_vec->Lookup(i)->AsStringVal(); - const uint8 *data = sv->Bytes(); - X509* x = d2i_X509_(NULL, &data, sv->Len()); - if ( ! x ) - { - X509_free(cert); - sk_X509_pop_free(untrusted_certs, X509_free); - builtin_error(fmt("Untrusted certificate stack creation error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); - return new Val((uint64) ERR_get_error(), TYPE_COUNT); - } - sk_X509_push(untrusted_certs, x); - } - - X509_STORE_CTX csc; - X509_STORE_CTX_init(&csc, ctx, cert, untrusted_certs); - X509_STORE_CTX_set_time(&csc, 0, (time_t) network_time); - - int result = X509_verify_cert(&csc); - X509_STORE_CTX_cleanup(&csc); - - if ( untrusted_certs ) - sk_X509_pop_free(untrusted_certs, X509_free); - X509_free(cert); - - return new Val((uint64) csc.error, TYPE_COUNT); - %} - -## Converts a certificate verification error code into an ASCII string. -## -## err_num: The error code. -## -## Returns: A string representation of *err_num*. -## -## .. bro:see:: x509_verify -function x509_err2str%(err_num: count%): string - %{ - return new StringVal(X509_verify_cert_error_string(err_num)); - %} diff --git a/src/analyzer/protocol/ssl/ssl-analyzer.pac b/src/analyzer/protocol/ssl/ssl-analyzer.pac index 43e2ac5c73..4bf1e27d64 100644 --- a/src/analyzer/protocol/ssl/ssl-analyzer.pac +++ b/src/analyzer/protocol/ssl/ssl-analyzer.pac @@ -8,9 +8,6 @@ #include "util.h" -#include -#include - #include "file_analysis/Manager.h" %} @@ -247,57 +244,13 @@ refine connection SSL_Conn += { if ( certificates->size() == 0 ) return true; - if ( x509_certificate ) + for ( unsigned int i = 0; i < certificates->size(); ++i ) { - STACK_OF(X509)* untrusted_certs = 0; + const bytestring& cert = (*certificates)[i]; - for ( unsigned int i = 0; i < certificates->size(); ++i ) - { - const bytestring& cert = (*certificates)[i]; - const uint8* data = cert.data(); - - file_mgr->DataIn(reinterpret_cast(data), cert.length(), - bro_analyzer()->GetAnalyzerTag(), bro_analyzer()->Conn(), false); - file_mgr->EndOfFile(bro_analyzer()->GetAnalyzerTag(), bro_analyzer()->Conn()); - - X509* pTemp = d2i_X509_binpac(NULL, &data, cert.length()); - if ( ! pTemp ) - { - BifEvent::generate_x509_error(bro_analyzer(), bro_analyzer()->Conn(), - ${rec.is_orig}, ERR_get_error()); - return false; - } - - - RecordVal* pX509Cert = new RecordVal(x509_type); - char tmp[256]; - BIO *bio = BIO_new(BIO_s_mem()); - - pX509Cert->Assign(0, new Val((uint64) X509_get_version(pTemp), TYPE_COUNT)); - i2a_ASN1_INTEGER(bio, X509_get_serialNumber(pTemp)); - int len = BIO_read(bio, &(*tmp), sizeof tmp); - pX509Cert->Assign(1, new StringVal(len, tmp)); - - X509_NAME_print_ex(bio, X509_get_subject_name(pTemp), 0, XN_FLAG_RFC2253); - len = BIO_gets(bio, &(*tmp), sizeof tmp); - pX509Cert->Assign(2, new StringVal(len, tmp)); - X509_NAME_print_ex(bio, X509_get_issuer_name(pTemp), 0, XN_FLAG_RFC2253); - len = BIO_gets(bio, &(*tmp), sizeof tmp); - pX509Cert->Assign(3, new StringVal(len, tmp)); - BIO_free(bio); - - pX509Cert->Assign(4, new Val(get_time_from_asn1(X509_get_notBefore(pTemp)), TYPE_TIME)); - pX509Cert->Assign(5, new Val(get_time_from_asn1(X509_get_notAfter(pTemp)), TYPE_TIME)); - StringVal* der_cert = new StringVal(cert.length(), (const char*) cert.data()); - - BifEvent::generate_x509_certificate(bro_analyzer(), bro_analyzer()->Conn(), - ${rec.is_orig}, - pX509Cert, - i, certificates->size(), - der_cert); - - X509_free(pTemp); - } + file_mgr->DataIn(reinterpret_cast(cert.data()), cert.length(), + bro_analyzer()->GetAnalyzerTag(), bro_analyzer()->Conn(), ${rec.is_orig}); + file_mgr->EndOfFile(bro_analyzer()->GetAnalyzerTag(), bro_analyzer()->Conn()); } return true; %} From 7025d511e47a49defb44e234f2de2eaf79047112 Mon Sep 17 00:00:00 2001 From: Daniel Thayer Date: Wed, 13 Nov 2013 16:45:43 -0600 Subject: [PATCH 004/254] Update the documentation of types and attributes Documented the new substring extraction functionality. Clarified the description of "&priority" and "void". Also fixed various typos. --- doc/scripts/builtins.rst | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/doc/scripts/builtins.rst b/doc/scripts/builtins.rst index aa1a097683..85e9cd14c8 100644 --- a/doc/scripts/builtins.rst +++ b/doc/scripts/builtins.rst @@ -23,7 +23,8 @@ The Bro scripting language supports the following built-in types. .. bro:type:: void - An internal Bro type representing the absence of a return type for a + An internal Bro type (i.e., "void" is not a reserved keyword in the Bro + scripting language) representing the absence of a return type for a function. .. bro:type:: bool @@ -132,10 +133,23 @@ The Bro scripting language supports the following built-in types. Strings support concatenation (``+``), and assignment (``=``, ``+=``). Strings also support the comparison operators (``==``, ``!=``, ``<``, - ``<=``, ``>``, ``>=``). Substring searching can be performed using - the "in" or "!in" operators (e.g., "bar" in "foobar" yields true). - The number of characters in a string can be found by enclosing the - string within pipe characters (e.g., ``|"abc"|`` is 3). + ``<=``, ``>``, ``>=``). The number of characters in a string can be + found by enclosing the string within pipe characters (e.g., ``|"abc"|`` + is 3). + + The subscript operator can extract an individual character or a substring + of a string (string indexing is zero-based, but an index of + -1 refers to the last character in the string, and -2 refers to the + second-to-last character, etc.). When extracting a substring, the + starting and ending index values are separated by a colon. For example:: + + local orig = "0123456789"; + local third_char = orig[2]; + local last_char = orig[-1]; + local first_three_chars = orig[0:2]; + + Substring searching can be performed using the "in" or "!in" + operators (e.g., "bar" in "foobar" yields true). Note that Bro represents strings internally as a count and vector of bytes rather than a NUL-terminated byte string (although string @@ -767,7 +781,7 @@ The Bro scripting language supports the following built-in types. .. bro:type:: hook A hook is another flavor of function that shares characteristics of - both a :bro:type:`function` and a :bro:type:`event`. They are like + both a :bro:type:`function` and an :bro:type:`event`. They are like events in that many handler bodies can be defined for the same hook identifier and the order of execution can be enforced with :bro:attr:`&priority`. They are more like functions in the way they @@ -856,14 +870,14 @@ scripting language supports the following built-in attributes. .. bro:attr:: &optional Allows a record field to be missing. For example the type ``record { - a: int, b: port &optional }`` could be instantiated both as + a: addr; b: port &optional; }`` could be instantiated both as singleton ``[$a=127.0.0.1]`` or pair ``[$a=127.0.0.1, $b=80/tcp]``. .. bro:attr:: &default Uses a default value for a record field, a function/hook/event parameter, or container elements. For example, ``table[int] of - string &default="foo" }`` would create a table that returns the + string &default="foo"`` would create a table that returns the :bro:type:`string` ``"foo"`` for any non-existing index. .. bro:attr:: &redef @@ -901,7 +915,7 @@ scripting language supports the following built-in attributes. Called right before a container element expires. The function's first parameter is of the same type of the container and the second parameter the same type of the container's index. The return - value is a :bro:type:`interval` indicating the amount of additional + value is an :bro:type:`interval` indicating the amount of additional time to wait before expiring the container element at the given index (which will trigger another execution of this function). @@ -925,7 +939,7 @@ scripting language supports the following built-in attributes. .. bro:attr:: &persistent - Makes a variable persistent, i.e., its value is writen to disk (per + Makes a variable persistent, i.e., its value is written to disk (per default at shutdown time). .. bro:attr:: &synchronized @@ -957,8 +971,9 @@ scripting language supports the following built-in attributes. .. bro:attr:: &priority - Specifies the execution priority of an event handler. Higher values - are executed before lower ones. The default value is 0. + Specifies the execution priority (as a signed integer) of a hook or + event handler. Higher values are executed before lower ones. The + default value is 0. .. bro:attr:: &group From a33d25b3bd2ce7c00b398fb6322e2c7c6abd2fc9 Mon Sep 17 00:00:00 2001 From: Rafael Bonilla Date: Thu, 21 Nov 2013 12:56:00 -0600 Subject: [PATCH 005/254] New Bro Manual Development Edition and basic.css to fix btest output overflow problem (Update 1). --- doc/_static/basic.css | 9 ++ doc/broids/index.rst | 155 ++++++++++++++++++++ doc/httpmonitor/index.rst | 256 ++++++++++++++++++++++++++++++++++ doc/index.rst | 38 ++++- doc/{using => logs}/index.rst | 49 +++++++ doc/mimestats/index.rst | 145 +++++++++++++++++++ 6 files changed, 647 insertions(+), 5 deletions(-) create mode 100644 doc/broids/index.rst create mode 100644 doc/httpmonitor/index.rst rename doc/{using => logs}/index.rst (73%) create mode 100644 doc/mimestats/index.rst diff --git a/doc/_static/basic.css b/doc/_static/basic.css index 1332c7b048..26e3450b65 100644 --- a/doc/_static/basic.css +++ b/doc/_static/basic.css @@ -439,8 +439,17 @@ td.linenos pre { color: #aaa; } +.highlight-guess { + overflow:auto; +} + +.highlight-none { + overflow:auto; +} + table.highlighttable { margin-left: 0.5em; + overflow:scroll; } table.highlighttable td { diff --git a/doc/broids/index.rst b/doc/broids/index.rst new file mode 100644 index 0000000000..dd0a0e8b22 --- /dev/null +++ b/doc/broids/index.rst @@ -0,0 +1,155 @@ +__ http://www.bro.org/sphinx-git/scripts/base/protocols/ftp/main.bro.html#id-FTP::parse_ftp_reply_code +__ http://www.bro.org/sphinx-git/frameworks/sumstats.html +__ http://www.bro.org/sphinx-git/frameworks/notice.html +__ http://www.bro.org/sphinx-git/_downloads/detect-bruteforcing.bro +__ http://www.bro.org/sphinx-git/scripts/policy/frameworks/files/detect-MHR.bro.html + +.. _bro-ids: + +======= +Bro IDS +======= + +An Intrusion Detection System (IDS) allows you to detect suspicious activities happening on your network as a result of a past or active +attack. Because of its programming capabilities, Bro can easily be configured to behave like traditional IDSs and detect common attacks +with well known patterns, or you can create your own scripts to detect conditions specific to your particular case. + +In the following sections, we present a few examples of common uses of Bro as an IDS. + +------------------------------------------------ +Detecting an FTP Bruteforce attack and notifying +------------------------------------------------ +For the purpose of this exercise, we define FTP bruteforcing as too many rejected usernames and passwords occurring from a single address. +We start by defining a threshold for the number of attempts and a monitoring interval in minutes. + + .. code:: bro + + export { + ## How many rejected usernames or passwords are required before being + ## considered to be bruteforcing. + const bruteforce_threshold: double = 20 &redef; + + ## The time period in which the threshold needs to be crossed before + ## being reset. + const bruteforce_measurement_interval = 15mins &redef; + } + +Now, using the ftp_reply event, we check for error codes from the `500 series `_ for the "USER" and "PASS" commands, representing rejected usernames or passwords. For this, we can use the `FTP::parse_ftp_reply`__ function to break down the reply code and check if the first digit is a "5" or not. If true, we then use the `SumStats`__ framework to keep track of the number of failed attempts. + + .. code:: bro + + event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) + { + local cmd = c$ftp$cmdarg$cmd; + if ( cmd == "USER" || cmd == "PASS" ) + { + if ( FTP::parse_ftp_reply_code(code)$x == 5 ) + SumStats::observe("ftp.failed_auth", [$host=c$id$orig_h], [$str=cat(c$id$resp_h)]); + } + } + +Next, we use the SumStats framework to automatically print a message on the console alerting of the attack when the number of failed attempts +exceeds the specified threshold during the measuring interval. + + .. code:: bro + + event bro_init() + { + local r1: SumStats::Reducer = [$stream="ftp.failed_auth", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(bruteforce_threshold+2)]; + SumStats::create([$name="ftp-detect-bruteforcing", + $epoch=bruteforce_measurement_interval, + $reducers=set(r1), + $threshold_val(key: SumStats::Key, result: SumStats::Result) = + { + return result["ftp.failed_auth"]$num+0.0; + }, + $threshold=bruteforce_threshold, + $threshold_crossed(key: SumStats::Key, result: SumStats::Result) = + { + local r = result["ftp.failed_auth"]; + local dur = duration_to_mins_secs(r$end-r$begin); + local plural = r$unique>1 ? "s" : ""; + local message = fmt("%s had %d failed logins on %d FTP server%s in %s", key$host, r$num, r$unique, plural, dur); + }]); + } + +Printing a message on the console is a good start but it will be better if we raise an alarm instead using the `Notice`__ framework. For this, we need to define a new Notice type and trigger the alarm under the right +conditions. Below is the final code for our script. + + .. code:: bro + + ##! FTP brute-forcing detector, triggering when too many rejected usernames or + ##! failed passwords have occurred from a single address. + + @load base/protocols/ftp + @load base/frameworks/sumstats + + @load base/utils/time + + module FTP; + + export { + redef enum Notice::Type += { + ## Indicates a host bruteforcing FTP logins by watching for too + ## many rejected usernames or failed passwords. + Bruteforcing + }; + + ## How many rejected usernames or passwords are required before being + ## considered to be bruteforcing. + const bruteforce_threshold: double = 20 &redef; + + ## The time period in which the threshold needs to be crossed before + ## being reset. + const bruteforce_measurement_interval = 15mins &redef; + } + + + event bro_init() + { + local r1: SumStats::Reducer = [$stream="ftp.failed_auth", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(bruteforce_threshold+2)]; + SumStats::create([$name="ftp-detect-bruteforcing", + $epoch=bruteforce_measurement_interval, + $reducers=set(r1), + $threshold_val(key: SumStats::Key, result: SumStats::Result) = + { + return result["ftp.failed_auth"]$num+0.0; + }, + $threshold=bruteforce_threshold, + $threshold_crossed(key: SumStats::Key, result: SumStats::Result) = + { + local r = result["ftp.failed_auth"]; + local dur = duration_to_mins_secs(r$end-r$begin); + local plural = r$unique>1 ? "s" : ""; + local message = fmt("%s had %d failed logins on %d FTP server%s in %s", key$host, r$num, r$unique, plural, dur); + NOTICE([$note=FTP::Bruteforcing, + $src=key$host, + $msg=message, + $identifier=cat(key$host)]); + }]); + } + + event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) + { + local cmd = c$ftp$cmdarg$cmd; + if ( cmd == "USER" || cmd == "PASS" ) + { + if ( FTP::parse_ftp_reply_code(code)$x == 5 ) + SumStats::observe("ftp.failed_auth", [$host=c$id$orig_h], [$str=cat(c$id$resp_h)]); + } + } + +As a final note, the `detect-bruteforcing.bro`__ script above is include with Bro out of the box, so you only need to load it at startup to instruct Bro to detect and notify of FTP bruteforce attacks. + +------------- +Other Attacks +------------- +Detecting SQL Injection attacks +------------------------------- +Checking files against known malware hashes +------------------------------------------- +Files transmitted on your network could either be completely harmless or contain viruses and other threats. One possible action against +this threat is to compute the hashes of the files and compare them against a list of known malware hashes. Bro simplifies this task +by offering a `detect-MHR.bro`__ script that creates and compares +hashes against the `Malware Hash Registry `_ maintained by Team Cymru. You only need to load this +script along with your other scripts at startup time. diff --git a/doc/httpmonitor/index.rst b/doc/httpmonitor/index.rst new file mode 100644 index 0000000000..41f9dd955c --- /dev/null +++ b/doc/httpmonitor/index.rst @@ -0,0 +1,256 @@ +__ http://www.bro.org/sphinx-git/scripts/base/protocols/http/main.bro.html +__ http://www.bro.org/sphinx-git/frameworks/file-analysis.html + +.. _http-monitor: + +================================ +Monitoring HTTP Traffic with Bro +================================ + +Bro can be used to log the entire HTTP traffic from your network to the http.log file. +This file can then be used for analysis and auditing purposes. + +In the sections below we briefly explain the structure of the http.log file. Then, we +show you how to perform basic HTTP traffic monitoring and analysis tasks with Bro. Some +of these ideas and techniques can later be applied to monitor different protocols in a +similar way. + +---------------------------- +Introduction to the HTTP log +---------------------------- + +The http.log file contains a summary of all HTTP requests and responses sent over a Bro-monitored +network. Here are the first few columns of +``http.log``:: + + # ts uid orig_h orig_p resp_h resp_p + 1311627961.8 HSH4uV8KVJg 192.168.1.100 52303 192.150.187.43 80 + +Every single line in this log starts with a timestamp, a unique connection identifier (UID), and a +connection 4-tuple (originator host/port and responder host/port). The UID can be used to +identify all logged activity (possibly across multiple log files) associated +with a given connection 4-tuple over its lifetime. + +The remaining columns detail the activity that's occurring. For example, the columns on the line below +(shortened for brevity) show a request to the root of Bro website:: + + # method host uri referrer user_agent + GET bro.org / - <...>Chrome/12.0.742.122<...> + +Network administrators and security engineers, for instance, can use the information in this log to understand +the HTTP activity on the network and troubleshoot network problems or search for anomalous activities. At this +point, we would like to stress out the fact that there is no just one right way to perform analysis; it will +depend on the expertise of the person doing the analysis and the specific details of the task to accomplish. + +For more information about how to handle the HTTP protocol in Bro, including a complete list +of the fields available in http.log, go to Bro's HTTP reference `page`__. + +------------------------ +Detecting a Proxy Server +------------------------ + +A proxy server is a device on your network configured to request a service on behalf of a third system; one of the +most common examples is a Web proxy server. A client without Internet access connects to the proxy and requests +a Web page; the proxy then sends the request to the actual Web server, receives the response and passes it to the original +client. + +Proxies were conceived to help manage a network and provide better encapsulation. By themselves, proxies are not a security +threat, but a misconfigured or unauthorized proxy can allow others, either inside or outside the network, to access any +Web site and even conduct malicious activities anonymously using the network resources. + +What Proxy Server traffic looks like +------------------------------------- + +In general, when a client starts talking with a proxy server, the traffic consists of two parts: (i) a GET request, and +(ii) an HTTP/ reply:: + + Request: GET http://www.bro.org/ HTTP/1.1 + Reply: HTTP/1.0 200 OK + +This will differ from traffic between a client and a normal Web server because GET requests should not include "http" on +the string. So we can use this to identify a proxy server. + +We can write a basic script in Bro to handle the http_reply event and detect a reply for a ``GET http://`` request. + + .. code:: bro + + event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code == 200 ) + { + print fmt("A local server is acting as an open proxy: ", c$id$resp_h); + } + } + +Basically, the script is checking for a "200 OK" status code on a reply for a request that includes "http:". In reality, the HTTP +protocol defines several success status codes other than 200, so we will extend our basic script to also consider the additional codes. + + .. code:: bro + + export { + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; + + } + + event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code in success_status_codes ) + { + print fmt("A local server is acting as an open proxy: ", c$id$resp_h); + } + } + +Next, we will make sure that the responding proxy is part of our local network. + + .. code:: bro + + export { + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; + + } + + event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( Site::is_local_addr(c$id$resp_h) && /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code in success_status_codes ) + { + print fmt("A local server is acting as an open proxy: ", c$id$resp_h); + } + } + +Finally, our goal should be to generate an alert when a proxy has been detected instead of printing a message on the console output. +For that, we will tag the traffic accordingly and define a new ``Open_Proxy`` ``Notice`` type to alert of all tagged communications. Once a +notification has been fired, we will further suppress it for one day. Below is the complete script. + + .. code:: bro + + @load base/frameworks/notice + + module HTTP; + + export { + + redef enum HTTP::Tags += { + OPEN_PROXY_TAG + }; + redef enum Notice::Type += { + Open_Proxy + }; + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; + + } + + redef Notice::emailed_types += { + Open_Proxy, + }; + + function open_proxy_only(rec: HTTP::Info) : bool + { + # Only write out connections with the OPEN_PROXY_TAG. + return OPEN_PROXY_TAG in rec$tags; + } + + event http_reply(c: connection, version: string, code: count, reason: string) + { + # make sure responding host is local + #if ( Site::is_local_addr(c$id$resp_h) && /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code in success_status_codes ) + { + add c$http$tags[OPEN_PROXY_TAG]; + local ident = cat(c$id$resp_h); + if ( c$http?$host ) #check if the optional host field exists in http + { + print fmt("Originator host: %s", c$id$orig_h); + NOTICE([$note=HTTP::Open_Proxy, + $msg=cat("A local server is acting as an open proxy: ", c$id$resp_h), + $conn=c, $identifier=cat(ident, c$id$resp_h), + $suppress_for=1day]); + } + } + } + + event bro_init() + { + #Creating a new filter for all open proxy logs. + local filter: Log::Filter = [$name="open_proxy", $path="open_proxy", $pred=open_proxy_only]; + Log::add_filter(HTTP::LOG, filter); + } + +---------------- +Inspecting Files +---------------- + +Files are often transmitted on regular HTTP conversations between a client and a server. Most of the time these files are harmless, +just images and some other multimedia content, but there are also types of files, specially executable files, that can damage +your system. We can instruct Bro to create a copy of all executable files that it sees for later analysis using the `File Analysis +Framework`__ (introduced with Bro 2.2) as shown in the following script. + + .. code:: bro + + global ext_map: table[string] of string = { + ["application/x-dosexec"] = "exe", + } &default =""; + + event file_new(f: fa_file) + { + local ext = ""; + + if ( f?$mime_type ) + ext = ext_map[f$mime_type]; + + local fname = fmt("%s-%s.%s", f$source, f$id, ext); + Files::add_analyzer(f, Files::ANALYZER_EXTRACT, [$extract_filename=fname]); + } + +Bro will extract all files from the traffic and write them on a new ``extract_files/`` subdirectory and change the file name with the right +suffix (extension) based on the content of the ext_map table. So, if you want to do the same for other extracted files besides executables +you just need to add those types to the ``ext_map`` table like this. + + .. code:: bro + + global ext_map: table[string] of string = { + ["application/x-dosexec"] = "exe", + ["text/plain"] = "txt", + ["image/jpeg"] = "jpg", + ["image/png"] = "png", + ["text/html"] = "html", + } &default =""; + +Bro will now write the appropriate suffix for text, JPEG, PNG, and HTML files stored in the ``extract_files/`` subdirectory. diff --git a/doc/index.rst b/doc/index.rst index 34096694b3..98006034c2 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,9 +1,12 @@ .. Bro documentation master file -================= -Bro Documentation -================= +========== +Bro Manual +========== + +Introduction Section +==================== .. toctree:: :maxdepth: 2 @@ -11,13 +14,38 @@ Bro Documentation intro/index.rst install/index.rst quickstart/index.rst - using/index.rst + +.. + +Using Bro Section +================= + +.. toctree:: + :maxdepth: 2 + + logs/index.rst + httpmonitor/index.rst + broids/index.rst + mimestats/index.rst + cluster/index.rst + +.. + +Reference Section +================= + +.. toctree:: + :maxdepth: 2 + scripting/index.rst frameworks/index.rst - cluster/index.rst script-reference/index.rst components/index.rst +.. + +* `Notice Index `_ (TODO: Move to reference + section, but can't figure out how to include it into toctree) * :ref:`General Index ` * :ref:`search` diff --git a/doc/using/index.rst b/doc/logs/index.rst similarity index 73% rename from doc/using/index.rst rename to doc/logs/index.rst index 1ad05d74f8..a6844d6e03 100644 --- a/doc/using/index.rst +++ b/doc/logs/index.rst @@ -1,3 +1,13 @@ +__ http://www.bro.org/sphinx-git/scripts/base/protocols/http/main.bro.html#type-HTTP::Info +__ http://www.bro.org/sphinx-git/scripts/base/protocols/ftp/info.bro.html#type-FTP::Info +__ http://www.bro.org/sphinx-git/scripts/base/protocols/ssl/main.bro.html#type-SSL::Info +__ http://www.bro.org/sphinx-git/scripts/policy/protocols/ssl/known-certs.bro.html#type-Known::CertsInfo +__ http://www.bro.org/sphinx-git/scripts/base/protocols/smtp/main.bro.html#type-SMTP::Info +__ http://www.bro.org/sphinx-git/scripts/base/protocols/dns/main.bro.html#type-DNS::Info +__ http://www.bro.org/sphinx-git/scripts/base/protocols/conn/main.bro.html#type-Conn::Info +__ http://www.bro.org/sphinx-git/scripts/base/frameworks/dpd/main.bro.html#type-DPD::Info +__ http://www.bro.org/sphinx-git/scripts/base/frameworks/files/main.bro.html#type-Files::Info +__ http://www.bro.org/sphinx-git/scripts/base/frameworks/notice/weird.bro.html#type-Weird::Info .. _using-bro: @@ -251,3 +261,42 @@ stream and Bro is able to extract and track that information for you, giving you an in-depth and structured view into HTTP traffic on your network. +----------------------- +Common Log Files +----------------------- +As a monitoring tool, Bro records a detailed view of the traffic inspected and the events generated in +a series of relevant log files. These files can later be reviewed for monitoring, auditing and troubleshooting +purposes. + +In this section we present a brief explanation of the most commonly used log files generated by Bro including links +to descriptions of some of the fields for each log type. + ++-----------------+---------------------------------------+------------------------------+ +| Log File | Description | Field Descriptions | ++=================+=======================================+==============================+ +| http.log | Shows all HTTP requests and replies | :bro:type:`HTTP::Info` | ++-----------------+---------------------------------------+------------------------------+ +| ftp.log | Records FTP activity | :bro:type:`FTP::Info` | ++-----------------+---------------------------------------+------------------------------+ +| ssl.log | Records SSL sessions including | :bro:type:`SSL::Info` | +| | certificates used | | ++-----------------+---------------------------------------+------------------------------+ +| known_certs.log | Includes SSL certificates used | :bro:type:`Known::CertsInfo` | ++-----------------+---------------------------------------+------------------------------+ +| smtp.log | Summarizes SMTP traffic on a network | :bro:type:`SMTP::Info` | ++-----------------+---------------------------------------+------------------------------+ +| dns.log | Shows all DNS activity on a network | :bro:type:`DNS::Info` | ++-----------------+---------------------------------------+------------------------------+ +| conn.log | Records all connections seen by Bro | :bro:type:`Conn::Info` | ++-----------------+---------------------------------------+------------------------------+ +| dpd.log | Shows network activity on | :bro:type:`DPD::Info` | +| | non-standard ports | | ++-----------------+---------------------------------------+------------------------------+ +| files.log | Records information about all files | :bro:type:`Files::Info` | +| | transmitted over the network | | ++-----------------+---------------------------------------+------------------------------+ +| weird.log | Records unexpected protocol-level | :bro:type:`Weird::Info` | +| | activity | | ++-----------------+---------------------------------------+------------------------------+ + + diff --git a/doc/mimestats/index.rst b/doc/mimestats/index.rst new file mode 100644 index 0000000000..903131acd5 --- /dev/null +++ b/doc/mimestats/index.rst @@ -0,0 +1,145 @@ +__ http://www.bro.org/sphinx-git/frameworks/sumstats.html + +.. _mime-stats: + +==================== +MIME Type Statistics +==================== + +Files are constantly transmitted over HTTP on regular networks. These files belong to a specific category (i.e., executable, text, image, etc.) identified +by a `Multipurpose Internet Mail Extension (MIME) `_. Although MIME was originally developed to identify the type of +non-text attachments on email, it is also used by Web browser to identify the type of files transmitted and present them accordingly. + +In this tutorial, we will show how to use the Sumstats Framework to collect some statistics information based on MIME types, specifically the total number of +occurrences, size in bytes, and number of unique hosts transmitting files over HTTP per each type. For instructions about extracting and creating a local copy +of these files, visit `this <../httpmonitor/index.html#inspecting-files>`_ tutorial instead. + +------------------------------------------------ +MIME Statistics with Sumstats +------------------------------------------------ +When working with the `Sumstats`__ framework, you need to define three different pieces: (i) Observations, where +the event is observed and fed into the framework. (ii) Reducers, where observations are collected and measured. (iii) Sumstats, where the main functionality +is implemented. + +So, we start by defining our observation along with a record to store all statistics values and an observation interval. We are conducting our observation on +the `HTTP::log_http` event and we are interested in the MIME type, size of the file ("response_body_len") and the originator host ("orig_h"). We use the MIME +type as our key and create observers for the other two values. + + .. code:: bro + + export { + redef enum Log::ID += { LOG }; + type Info: record { + ## Timestamp when the log line was finished and written. + ts: time &log; + ## Time interval that the log line covers. + ts_delta: interval &log; + ## The mime type + mtype: string &log; + ## The number of unique local hosts that fetched this mime type + uniq_hosts: count &log; + ## The number of hits to the mime type + hits: count &log; + ## The total number of bytes received by this mime type + bytes: count &log; + }; + + ## The frequency of logging the stats collected by this script. + const break_interval = 5mins &redef; + } + + event HTTP::log_http(rec: HTTP::Info) + { + if(Site::is_local_addr(rec$id$orig_h) && rec?$resp_mime_types) { + local mime_type = rec$resp_mime_types[0]; + SumStats::observe("mime.bytes", [$str=mime_type], [$num=rec$response_body_len]); + SumStats::observe("mime.hits", [$str=mime_type], [$str=cat(rec$id$orig_h)]); + } + } + +Next, we create the reducers. The first one will accumulate file sizes and the second one will make sure we only store a host ID once. Below is the partial code. + + .. code:: bro + + local r1: SumStats::Reducer = [$stream="mime.bytes", $apply=set(SumStats::SUM)]; + local r2: SumStats::Reducer = [$stream="mime.hits", $apply=set(SumStats::UNIQUE)]; + +In our final step, we create the SumStats where we check for the observation interval and once it expires, we populate the record (defined above) with all the +relevant data and write it to a log. + + .. code:: bro + + SumStats::create([$name="mime-metrics", + $epoch=break_interval, + $reducers=set(r1, r2), + $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) = + { + local l: Info; + l$ts = network_time(); + l$ts_delta = break_interval; + l$mtype = key$str; + l$bytes = double_to_count(floor(result["mime.bytes"]$sum)); + l$hits = result["mime.hits"]$num; + l$uniq_hosts = result["mime.hits"]$unique; + Log::write(LOG, l); + }]); + +Putting everything together we end up with the following final code for our script. + + .. code:: bro + + @load base/frameworks/sumstats + + module MimeMetrics; + + export { + redef enum Log::ID += { LOG }; + type Info: record { + ## Timestamp when the log line was finished and written. + ts: time &log; + ## Time interval that the log line covers. + ts_delta: interval &log; + ## The mime type + mtype: string &log; + ## The number of unique local hosts that fetched this mime type + uniq_hosts: count &log; + ## The number of hits to the mime type + hits: count &log; + ## The total number of bytes received by this mime type + bytes: count &log; + }; + + ## The frequency of logging the stats collected by this script. + const break_interval = 5mins &redef; + } + + event bro_init() &priority=3 + { + Log::create_stream(MimeMetrics::LOG, [$columns=Info]); + local r1: SumStats::Reducer = [$stream="mime.bytes", $apply=set(SumStats::SUM)]; + local r2: SumStats::Reducer = [$stream="mime.hits", $apply=set(SumStats::UNIQUE)]; + SumStats::create([$name="mime-metrics", + $epoch=break_interval, + $reducers=set(r1, r2), + $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) = + { + local l: Info; + l$ts = network_time(); + l$ts_delta = break_interval; + l$mtype = key$str; + l$bytes = double_to_count(floor(result["mime.bytes"]$sum)); + l$hits = result["mime.hits"]$num; + l$uniq_hosts = result["mime.hits"]$unique; + Log::write(LOG, l); + }]); + } + + event HTTP::log_http(rec: HTTP::Info) + { + if(Site::is_local_addr(rec$id$orig_h) && rec?$resp_mime_types) { + local mime_type = rec$resp_mime_types[0]; + SumStats::observe("mime.bytes", [$str=mime_type], [$num=rec$response_body_len]); + SumStats::observe("mime.hits", [$str=mime_type], [$str=cat(rec$id$orig_h)]); + } + } + From 6f06705c23cb52aa059ae98d770ecc1cb29a80a2 Mon Sep 17 00:00:00 2001 From: Daniel Thayer Date: Fri, 22 Nov 2013 14:49:16 -0600 Subject: [PATCH 006/254] Fix typos in BIF documentation Fixed typos in documentation of hexstr_to_bytestring. Also added documentation that was missing for function parameters and return values of other BIFs. --- src/bro.bif | 20 +++++++++++--------- src/probabilistic/top-k.bif | 4 ++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/bro.bif b/src/bro.bif index 24dff3c77c..d789ef9f4e 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -973,6 +973,8 @@ function entropy_test_finish%(handle: opaque of entropy%): entropy_test_result ## ## prefix: A custom string prepended to the result. ## +## Returns: A string identifier that is unique. +## ## .. bro:see:: unique_id_from function unique_id%(prefix: string%) : string %{ @@ -987,6 +989,8 @@ function unique_id%(prefix: string%) : string ## ## prefix: A custom string prepended to the result. ## +## Returns: A string identifier that is unique. +## ## .. bro:see:: unique_id function unique_id_from%(pool: int, prefix: string%) : string %{ @@ -1857,8 +1861,8 @@ function global_ids%(%): id_table ## ## id: The global identifier. ## -## Returns the value of *id*. If *id* does not describe a valid identifier, the -## function returns the string ``""`` or ``""``. +## Returns: The value of *id*. If *id* does not describe a valid identifier, +## the string ``""`` or ``""`` is returned. function lookup_ID%(id: string%) : any %{ ID* i = global_scope()->Lookup(id->CheckString()); @@ -2632,15 +2636,15 @@ function bytestring_to_hexstr%(bytestring: string%): string return new StringVal(hexstr); %} -## Converts a hex-string into its binary representation. +## Converts a hex-string into its binary representation. ## For example, ``"3034"`` would be converted to ``"04"``. ## -## The input string is assumed to only contain 0-9 and a-f, -## otherwhise behavior is undefines. +## The input string is assumed to contain an even number of hexadecimal digits +## (0-9, a-f, or A-F), otherwise behavior is undefined. ## -## hexstring: The hexadecimal string representation. +## hexstr: The hexadecimal string representation. ## -## Returns: The binary representation of *hexstring*. +## Returns: The binary representation of *hexstr*. ## ## .. bro:see:: hexdump bytestring_to_hexstr function hexstr_to_bytestring%(hexstr: string%): string @@ -4964,8 +4968,6 @@ function preserve_prefix%(a: addr, width: count%): any ## ## a: The subnet to preserve. ## -## width: The number of bits from the top that should remain intact. -## ## .. bro:see:: preserve_prefix anonymize_addr ## ## .. todo:: Currently dysfunctional. diff --git a/src/probabilistic/top-k.bif b/src/probabilistic/top-k.bif index e3dc891552..5362750467 100644 --- a/src/probabilistic/top-k.bif +++ b/src/probabilistic/top-k.bif @@ -138,6 +138,10 @@ function topk_sum%(handle: opaque of topk%): count ## Merge the second top-k data structure into the first. ## +## handle1: the first TopK handle. +## +## handle2: the second TopK handle. +## ## .. note:: This does not remove any elements, the resulting data structure ## can be bigger than the maximum size given on initialization. ## From 5b6468a302e275912418ac22da1a7d5cf9904eeb Mon Sep 17 00:00:00 2001 From: Daniel Thayer Date: Fri, 22 Nov 2013 16:36:08 -0600 Subject: [PATCH 007/254] Add documentation for event parameters Added documentation that was missing for some event parameters, and fixed documented name of event parameters. --- src/analyzer/protocol/dnp3/events.bif | 2 ++ src/analyzer/protocol/modbus/events.bif | 2 +- src/analyzer/protocol/tcp/events.bif | 4 ++-- src/event.bif | 6 +++++- src/file_analysis/analyzer/unified2/events.bif | 10 ++++++++++ 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/analyzer/protocol/dnp3/events.bif b/src/analyzer/protocol/dnp3/events.bif index a41f70897b..80f9504a9e 100644 --- a/src/analyzer/protocol/dnp3/events.bif +++ b/src/analyzer/protocol/dnp3/events.bif @@ -32,6 +32,8 @@ event dnp3_application_response_header%(c: connection, is_orig: bool, fc: count, ## ## qua_field: qualifier field. ## +## number: TODO. +## ## rf_low: the structure of the range field depends on the qualified field. ## In some cases, the range field contains only one logic part, e.g., ## number of objects, so only *rf_low* contains useful values. diff --git a/src/analyzer/protocol/modbus/events.bif b/src/analyzer/protocol/modbus/events.bif index dbbd7b78bb..537820f37d 100644 --- a/src/analyzer/protocol/modbus/events.bif +++ b/src/analyzer/protocol/modbus/events.bif @@ -149,7 +149,7 @@ event modbus_write_single_register_response%(c: connection, headers: ModbusHeade ## ## start_address: The memory address of the first coil to be written. ## -## value: The values to be written to the coils. +## coils: The values to be written to the coils. event modbus_write_multiple_coils_request%(c: connection, headers: ModbusHeaders, start_address: count, coils: ModbusCoils%); ## Generated for a Modbus write multiple coils response. diff --git a/src/analyzer/protocol/tcp/events.bif b/src/analyzer/protocol/tcp/events.bif index 216691dea1..cac18bfa3e 100644 --- a/src/analyzer/protocol/tcp/events.bif +++ b/src/analyzer/protocol/tcp/events.bif @@ -108,6 +108,8 @@ event connection_half_finished%(c: connection%); ## originator attempted to setup a TCP connection but the responder replied ## with a RST packet denying it. ## +## c: The connection. +## ## .. bro:see:: connection_EOF connection_SYN_packet connection_attempt ## connection_established connection_external connection_finished ## connection_first_ACK connection_half_finished connection_partial_close @@ -115,8 +117,6 @@ event connection_half_finished%(c: connection%); ## connection_status_update connection_timeout scheduled_analyzer_applied ## new_connection new_connection_contents partial_connection ## -## c: The connection. -## ## .. note:: ## ## If the responder does not respond at all, :bro:id:`connection_attempt` is diff --git a/src/event.bif b/src/event.bif index ddadb47f8a..bb0e98c7d6 100644 --- a/src/event.bif +++ b/src/event.bif @@ -591,7 +591,11 @@ event software_unparsed_version_found%(c: connection, host: addr, str: string%); ## and it raises this event for each system identified. The p0f fingerprints are ## defined by :bro:id:`passive_fingerprint_file`. ## -## TODO. +## c: The connection. +## +## host: The host running the reported OS. +## +## OS: The OS version string. ## ## .. bro:see:: passive_fingerprint_file software_parse_error ## software_version_found software_unparsed_version_found diff --git a/src/file_analysis/analyzer/unified2/events.bif b/src/file_analysis/analyzer/unified2/events.bif index c5f3dda6a4..a9134e5285 100644 --- a/src/file_analysis/analyzer/unified2/events.bif +++ b/src/file_analysis/analyzer/unified2/events.bif @@ -1,7 +1,17 @@ ## Abstract all of the various Unified2 event formats into ## a single event. +## +## f: The file. +## +## ev: TODO. +## event unified2_event%(f: fa_file, ev: Unified2::IDSEvent%); ## The Unified2 packet format event. +## +## f: The file. +## +## pkt: TODO. +## event unified2_packet%(f: fa_file, pkt: Unified2::Packet%); From cbe48258f66cefaba1f9f9100b0a5cf6f5c49d1f Mon Sep 17 00:00:00 2001 From: Justin Azoff Date: Tue, 10 Dec 2013 11:27:19 -0500 Subject: [PATCH 008/254] fix the caching of recently validated certs The recently_validated_certs table was being checked for entries, but missing hashes were not being added to it after validation. --- scripts/policy/protocols/ssl/validate-certs.bro | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/policy/protocols/ssl/validate-certs.bro b/scripts/policy/protocols/ssl/validate-certs.bro index b34ec5a09a..886c28b6ac 100644 --- a/scripts/policy/protocols/ssl/validate-certs.bro +++ b/scripts/policy/protocols/ssl/validate-certs.bro @@ -40,6 +40,7 @@ event ssl_established(c: connection) &priority=3 { local result = x509_verify(c$ssl$cert, c$ssl$cert_chain, root_certs); c$ssl$validation_status = x509_err2str(result); + recently_validated_certs[c$ssl$cert_hash] = c$ssl$validation_status; } if ( c$ssl$validation_status != "ok" ) From 63c36d58f3c622238a84d0d32b854d33ed5ccc9b Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 11 Dec 2013 14:23:19 -0600 Subject: [PATCH 009/254] Another attempt to improve core.when-interpreter-exceptions unit test. lookup_hostname("localhost") occassionally timed out (after allowed 10 secs) when running test suite on some systems. Not sure why, but changed to use the Exec module for when block conditions instead as the scope of the test doesn't depend on a particular type of condition, it just needs something that will work reliably/quickly. --- .../bro.output | 20 +++---- .../core/when-interpreter-exceptions.bro | 54 +++++++++++-------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/testing/btest/Baseline/core.when-interpreter-exceptions/bro.output b/testing/btest/Baseline/core.when-interpreter-exceptions/bro.output index 154734f6d3..6d7ae52baf 100644 --- a/testing/btest/Baseline/core.when-interpreter-exceptions/bro.output +++ b/testing/btest/Baseline/core.when-interpreter-exceptions/bro.output @@ -1,13 +1,13 @@ -1386110869.157209 expression error in /Users/jon/Projects/bro/bro/testing/btest/.tmp/core.when-interpreter-exceptions/when-interpreter-exceptions.bro, line 96: field value missing [p$ip] -1386110869.157209 expression error in /Users/jon/Projects/bro/bro/testing/btest/.tmp/core.when-interpreter-exceptions/when-interpreter-exceptions.bro, line 63: field value missing [p$ip] -1386110869.157209 expression error in /Users/jon/Projects/bro/bro/testing/btest/.tmp/core.when-interpreter-exceptions/when-interpreter-exceptions.bro, line 79: field value missing [p$ip] -1386110869.157209 expression error in /Users/jon/Projects/bro/bro/testing/btest/.tmp/core.when-interpreter-exceptions/when-interpreter-exceptions.bro, line 36: field value missing [p$ip] -1386110869.157209 received termination signal +expression error in /Users/jon/Projects/bro/bro/testing/btest/.tmp/core.when-interpreter-exceptions/when-interpreter-exceptions.bro, line 48: field value missing [myrecord$notset] +expression error in /Users/jon/Projects/bro/bro/testing/btest/.tmp/core.when-interpreter-exceptions/when-interpreter-exceptions.bro, line 92: field value missing [myrecord$notset] +expression error in /Users/jon/Projects/bro/bro/testing/btest/.tmp/core.when-interpreter-exceptions/when-interpreter-exceptions.bro, line 73: field value missing [myrecord$notset] +expression error in /Users/jon/Projects/bro/bro/testing/btest/.tmp/core.when-interpreter-exceptions/when-interpreter-exceptions.bro, line 104: field value missing [myrecord$notset] +received termination signal +[f(F)] +f() done, no exception, T +[f(T)] +[bro_init()] +timeout g(), T timeout timeout g(), F -timeout g(), T g() done, no exception, T -localhost resolved -localhost resolved from f(), T -localhost resolved from f(), F -f() done, no exception, T diff --git a/testing/btest/core/when-interpreter-exceptions.bro b/testing/btest/core/when-interpreter-exceptions.bro index 5918f80ab5..151d8d2f57 100644 --- a/testing/btest/core/when-interpreter-exceptions.bro +++ b/testing/btest/core/when-interpreter-exceptions.bro @@ -1,10 +1,19 @@ -# @TEST-EXEC: btest-bg-run bro "bro -b --pseudo-realtime -r $TRACES/rotation.trace %INPUT >output 2>&1" +# @TEST-EXEC: btest-bg-run bro "bro -b %INPUT >output 2>&1" # @TEST-EXEC: btest-bg-wait 15 # @TEST-EXEC: TEST_DIFF_CANONIFIER="$SCRIPTS/diff-remove-abspath | $SCRIPTS/diff-remove-timestamps | $SCRIPTS/diff-sort" btest-diff bro/output # interpreter exceptions in "when" blocks shouldn't cause termination -global p: pkt_hdr; +@load base/utils/exec +@load base/frameworks/communication # let network-time run. otherwise there are no heartbeats... +redef exit_only_after_terminate = T; + +type MyRecord: record { + a: bool &default=T; + notset: bool &optional; +}; + +global myrecord: MyRecord; global c = 0; @@ -26,22 +35,21 @@ event termination_check() function f(do_exception: bool): bool { - return when ( local addrs = lookup_hostname("localhost") ) + local cmd = Exec::Command($cmd=fmt("echo 'f(%s)'", + do_exception)); + + return when ( local result = Exec::run(cmd) ) { - print "localhost resolved from f()", do_exception; + print result$stdout; if ( do_exception ) { event termination_check(); - print p$ip; + print myrecord$notset; } return T; } - timeout 10 sec - { - print "lookup_hostname in f() timed out unexpectedly"; - } check_term_condition(); return F; @@ -49,9 +57,11 @@ function f(do_exception: bool): bool function g(do_exception: bool): bool { - return when ( local addrs = lookup_hostname("localhost") ) + local stall = Exec::Command($cmd="sleep 30"); + + return when ( local result = Exec::run(stall) ) { - print "shouldn't get here, g()", do_exception; + print "shouldn't get here, g()", do_exception, result; } timeout 0 sec { @@ -60,7 +70,7 @@ function g(do_exception: bool): bool if ( do_exception ) { event termination_check(); - print p$ip; + print myrecord$notset; } return T; @@ -72,28 +82,26 @@ function g(do_exception: bool): bool event bro_init() { - when ( local addrs = lookup_hostname("localhost") ) + local cmd = Exec::Command($cmd="echo 'bro_init()'"); + local stall = Exec::Command($cmd="sleep 30"); + + when ( local result = Exec::run(cmd) ) { - print "localhost resolved"; + print result$stdout; event termination_check(); - print p$ip; - } - timeout 10 sec - { - print "lookup_hostname timed out unexpectedly"; - check_term_condition(); + print myrecord$notset; } - when ( local addrs2 = lookup_hostname("localhost") ) + when ( local result2 = Exec::run(stall) ) { - print "shouldn't get here"; + print "shouldn't get here", result2; check_term_condition(); } timeout 0 sec { print "timeout"; event termination_check(); - print p$ip; + print myrecord$notset; } when ( local b = f(T) ) From 8ea56ae567c3bd7c1d7f6349c0507ef6afef3d4d Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 12 Dec 2013 13:26:19 -0600 Subject: [PATCH 010/254] Improve warnings emitted from raw/execute input reader. Some return values of the setpgid() call in that parent proc are ok (or contradict reality). --- src/input/readers/Raw.cc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/input/readers/Raw.cc b/src/input/readers/Raw.cc index d795430ba3..2bbdb4d0e0 100644 --- a/src/input/readers/Raw.cc +++ b/src/input/readers/Raw.cc @@ -204,9 +204,20 @@ bool Raw::Execute() // Parent also sets child process group immediately to avoid a race. if ( setpgid(childpid, childpid) == -1 ) { - char buf[256]; - strerror_r(errno, buf, sizeof(buf)); - Warning(Fmt("Could not set child process group: %s", buf)); + if ( errno == EACCES ) + // Child already did exec. That's fine since then it must have + // already done the setpgid() itself. + ; + else if ( errno == ESRCH && kill(childpid, 0) == 0 ) + // Sometimes (e.g. FreeBSD) this error is reported even though + // child exists, so do extra sanity check of whether it exists. + ; + else + { + char buf[256]; + strerror_r(errno, buf, sizeof(buf)); + Warning(Fmt("Could not set child process group: %s", buf)); + } } if ( ! UnlockForkMutex() ) From ae9e0d4cb6306967175d3e3321bcf03d94d6f49b Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Wed, 18 Dec 2013 08:36:50 -0800 Subject: [PATCH 011/254] Fixing segfault with mismatching set &default in record field. --- CHANGES | 5 +++++ VERSION | 2 +- src/Attr.cc | 5 +++-- .../Baseline/language.record-default-set-mismatch/out | 1 + testing/btest/language/record-default-set-mismatch.bro | 9 +++++++++ 5 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 testing/btest/Baseline/language.record-default-set-mismatch/out create mode 100644 testing/btest/language/record-default-set-mismatch.bro diff --git a/CHANGES b/CHANGES index 0d7fd7fca6..ce3b1f4de7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,9 @@ +2.2-75 | 2013-12-18 08:36:50 -0800 + + * Fixing segfault with mismatching set &default in record fields. + (Robin Sommer) + 2.2-74 | 2013-12-16 08:49:55 -0800 * Improve warnings emitted from raw/execute input reader. (Jon diff --git a/VERSION b/VERSION index 1a078d60da..9ee1a5bf6c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2-74 +2.2-75 diff --git a/src/Attr.cc b/src/Attr.cc index 244d1e1687..d6d0f6e68d 100644 --- a/src/Attr.cc +++ b/src/Attr.cc @@ -317,8 +317,9 @@ void Attributes::CheckAttr(Attr* a) break; // Table defaults may be promotable. - if ( (ytype->Tag() == TYPE_RECORD && atype->Tag() == TYPE_RECORD && - record_promotion_compatible(atype->AsRecordType(), ytype->AsRecordType())) ) + if ( ytype && ytype->Tag() == TYPE_RECORD && + atype->Tag() == TYPE_RECORD && + record_promotion_compatible(atype->AsRecordType(), ytype->AsRecordType()) ) // Ok. break; diff --git a/testing/btest/Baseline/language.record-default-set-mismatch/out b/testing/btest/Baseline/language.record-default-set-mismatch/out new file mode 100644 index 0000000000..c005138c0c --- /dev/null +++ b/testing/btest/Baseline/language.record-default-set-mismatch/out @@ -0,0 +1 @@ +error in /home/robin/bro/master/testing/btest/.tmp/language.record-default-set-mismatch/record-default-set-mismatch.bro, line 5: &default value has inconsistent type (&default=set(1, 2, 3)) diff --git a/testing/btest/language/record-default-set-mismatch.bro b/testing/btest/language/record-default-set-mismatch.bro new file mode 100644 index 0000000000..aab35321eb --- /dev/null +++ b/testing/btest/language/record-default-set-mismatch.bro @@ -0,0 +1,9 @@ +# @TEST-EXEC-FAIL: bro -b %INPUT 2>out +# @TEST-EXEC: btest-diff out + +type Foo: record { + a: set[string] &default=set(1,2,3); +}; + +global f: Foo; +print f; From 415fe678e2f0adb2eeae650099e9c9916b0f08c9 Mon Sep 17 00:00:00 2001 From: Daniel Thayer Date: Wed, 18 Dec 2013 14:31:56 -0600 Subject: [PATCH 012/254] Fixed typo in the Quick Start Guide Also clarified the instructions about modifying crontab. --- doc/quickstart/index.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/quickstart/index.rst b/doc/quickstart/index.rst index f570ac92db..7da5652c73 100644 --- a/doc/quickstart/index.rst +++ b/doc/quickstart/index.rst @@ -13,7 +13,7 @@ Bro works on most modern, Unix-based systems and requires no custom hardware. It can be downloaded in either pre-built binary package or source code forms. See :ref:`installing-bro` for instructions on how to install Bro. Below, ``$PREFIX`` is used to reference the Bro -installation root directory, which by default is ``/usr/local/`` if +installation root directory, which by default is ``/usr/local/bro/`` if you install from source. Managing Bro with BroControl @@ -26,8 +26,8 @@ traffic-monitoring cluster. A Minimal Starting Configuration -------------------------------- -These are the basic configuration changes to make for a minimal BroControl installation -that will manage a single Bro instance on the ``localhost``: +These are the basic configuration changes to make for a minimal BroControl +installation that will manage a single Bro instance on the ``localhost``: 1) In ``$PREFIX/etc/node.cfg``, set the right interface to monitor. 2) In ``$PREFIX/etc/networks.cfg``, comment out the default settings and add @@ -72,7 +72,8 @@ You can leave it running for now, but to stop this Bro instance you would do: [BroControl] > stop -We also recommend to insert the following entry into `crontab`:: +We also recommend to insert the following entry into the crontab of the user +running BroControl:: 0-59/5 * * * * $PREFIX/bin/broctl cron From 6bf8e892b3b0420a8b6c46920ca5bf2f6d73ae0d Mon Sep 17 00:00:00 2001 From: Daniel Thayer Date: Wed, 18 Dec 2013 14:51:08 -0600 Subject: [PATCH 013/254] Fix typo in Bro 2.2 NEWS The examples about string indexing for Bro 2.2 had a typo (comma should be colon). --- NEWS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 524cac14e0..2ed49bb929 100644 --- a/NEWS +++ b/NEWS @@ -198,9 +198,9 @@ New Functionality global s = MySet([$c=1], [$c=2]); - Strings now support the subscript operator to extract individual - characters and substrings (e.g., ``s[4]``, ``s[1,5]``). The index + characters and substrings (e.g., ``s[4]``, ``s[1:5]``). The index expression can take up to two indices for the start and end index of - the substring to return (e.g. ``mystring[1,3]``). + the substring to return (e.g. ``mystring[1:3]``). - Functions now support default parameters, e.g.:: From 58c7fcbbf134c771c8cd55b1354ad470190259bc Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 20 Dec 2013 11:44:06 -0600 Subject: [PATCH 014/254] Canonify output of a unit test. --- testing/btest/language/record-default-set-mismatch.bro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/btest/language/record-default-set-mismatch.bro b/testing/btest/language/record-default-set-mismatch.bro index aab35321eb..fcf10c1281 100644 --- a/testing/btest/language/record-default-set-mismatch.bro +++ b/testing/btest/language/record-default-set-mismatch.bro @@ -1,5 +1,5 @@ # @TEST-EXEC-FAIL: bro -b %INPUT 2>out -# @TEST-EXEC: btest-diff out +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out type Foo: record { a: set[string] &default=set(1,2,3); From 1411164d055a9fcd46e64fde4f06aacfc8f1d3ac Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Tue, 24 Dec 2013 07:38:17 -0800 Subject: [PATCH 015/254] Updating submodule(s). [nomail] --- aux/broctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/broctl b/aux/broctl index 2e07720b4f..2c6568efa9 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit 2e07720b4f129802e07ca99498e2aff4542c737a +Subproject commit 2c6568efa970aee29d863cdf3662ff62fdaed4e6 From ec3f684c610f084fdea8ed5cf85f9c4390eb58e6 Mon Sep 17 00:00:00 2001 From: Justin Azoff Date: Tue, 31 Dec 2013 10:09:44 -0500 Subject: [PATCH 016/254] change Notice::suppressing to be a table of times Instead of storing the entire notice in Notice::suppressing, just store the time the notice should be suppressed until. This has the same functionality, except that end_suppression can no longer be generated. --- scripts/base/frameworks/notice/cluster.bro | 3 ++- scripts/base/frameworks/notice/main.bro | 20 +++++--------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/scripts/base/frameworks/notice/cluster.bro b/scripts/base/frameworks/notice/cluster.bro index f197761acf..3c3fbc6d36 100644 --- a/scripts/base/frameworks/notice/cluster.bro +++ b/scripts/base/frameworks/notice/cluster.bro @@ -23,7 +23,8 @@ redef Cluster::worker2manager_events += /Notice::cluster_notice/; @if ( Cluster::local_node_type() != Cluster::MANAGER ) event Notice::begin_suppression(n: Notice::Info) { - suppressing[n$note, n$identifier] = n; + local suppress_until = n$ts + n$suppress_for; + suppressing[n$note, n$identifier] = suppress_until; } @endif diff --git a/scripts/base/frameworks/notice/main.bro b/scripts/base/frameworks/notice/main.bro index a5f17a4979..dac87662c4 100644 --- a/scripts/base/frameworks/notice/main.bro +++ b/scripts/base/frameworks/notice/main.bro @@ -242,12 +242,6 @@ export { ## being suppressed. global suppressed: event(n: Notice::Info); - ## This event is generated when a notice stops being suppressed. - ## - ## n: The record containing notice data regarding the notice type - ## that was being suppressed. - global end_suppression: event(n: Notice::Info); - ## Call this function to send a notice in an email. It is already used ## by default with the built in :bro:enum:`Notice::ACTION_EMAIL` and ## :bro:enum:`Notice::ACTION_PAGE` actions. @@ -285,27 +279,22 @@ export { } # This is used as a hack to implement per-item expiration intervals. -function per_notice_suppression_interval(t: table[Notice::Type, string] of Notice::Info, idx: any): interval +function per_notice_suppression_interval(t: table[Notice::Type, string] of time, idx: any): interval { local n: Notice::Type; local s: string; [n,s] = idx; - local suppress_time = t[n,s]$suppress_for - (network_time() - t[n,s]$ts); + local suppress_time = t[n,s] - network_time(); if ( suppress_time < 0secs ) suppress_time = 0secs; - # If there is no more suppression time left, the notice needs to be sent - # to the end_suppression event. - if ( suppress_time == 0secs ) - event Notice::end_suppression(t[n,s]); - return suppress_time; } # This is the internally maintained notice suppression table. It's # indexed on the Notice::Type and the $identifier field from the notice. -global suppressing: table[Type, string] of Notice::Info = {} +global suppressing: table[Type, string] of time = {} &create_expire=0secs &expire_func=per_notice_suppression_interval; @@ -467,7 +456,8 @@ hook Notice::notice(n: Notice::Info) &priority=-5 [n$note, n$identifier] !in suppressing && n$suppress_for != 0secs ) { - suppressing[n$note, n$identifier] = n; + local suppress_until = n$ts + n$suppress_for; + suppressing[n$note, n$identifier] = suppress_until; event Notice::begin_suppression(n); } } From 28673bd198ae6911cb137be956a7cc421210b98b Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Wed, 8 Jan 2014 21:47:38 -0500 Subject: [PATCH 017/254] Fix for traffic with TCP segmentation offloading with IP header len field being set to zero. --- src/Sessions.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Sessions.cc b/src/Sessions.cc index acc306d277..dcb3835469 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -384,6 +384,15 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, const struct ip* ip4 = ip_hdr->IP4_Hdr(); uint32 len = ip_hdr->TotalLen(); + if ( len == 0 ) + { + // TCP segmentation offloading can zero out the ip_len field. + Weird("ip_hdr_len_zero", hdr, pkt, encapsulation); + + // Cope with the zero'd out ip_len field by using the caplen. + len = hdr->caplen - hdr_size; + } + if ( hdr->len < len + hdr_size ) { Weird("truncated_IP", hdr, pkt, encapsulation); From 22f8bb9dd8a189e6a042041e76bca5bcbea0ad7a Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Wed, 8 Jan 2014 21:50:03 -0500 Subject: [PATCH 018/254] Fix for packet writing to make it use the global snaplength. --- src/PktSrc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PktSrc.cc b/src/PktSrc.cc index 9d6bce6fe9..941c4acd83 100644 --- a/src/PktSrc.cc +++ b/src/PktSrc.cc @@ -661,7 +661,7 @@ PktDumper::PktDumper(const char* arg_filename, bool arg_append) if ( linktype < 0 ) linktype = DLT_EN10MB; - pd = pcap_open_dead(linktype, 8192); + pd = pcap_open_dead(linktype, snaplen); if ( ! pd ) { Error("error for pcap_open_dead"); From beea92ce6ceb03c2d81f58635723bc1ec02646b9 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 10 Jan 2014 15:06:10 -0600 Subject: [PATCH 019/254] Broxygen init fixes, addresses BIT-1110. - Don't check mtime of bro binary if BRO_DISABLE_BROXYGEN env var set. - Fix failure to locate bro binary if invoking from a relative path and '.' isn't in PATH. --- src/broxygen/Manager.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/broxygen/Manager.cc b/src/broxygen/Manager.cc index 405a1019f9..51985a1e5c 100644 --- a/src/broxygen/Manager.cc +++ b/src/broxygen/Manager.cc @@ -35,8 +35,12 @@ Manager::Manager(const string& arg_config, const string& bro_command) if ( getenv("BRO_DISABLE_BROXYGEN") ) disabled = true; - const char* path = getenv("PATH"); - string path_to_bro = path ? find_file(bro_command, path): ""; + if ( disabled ) + return; + + const char* env_path = getenv("PATH"); + string path = env_path ? string(env_path) + ":." : "."; + string path_to_bro = find_file(bro_command, path); struct stat s; if ( path_to_bro.empty() || stat(path_to_bro.c_str(), &s) < 0 ) From e0082e6bcb7b346b87d9ad02a35dcab0209a351f Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 10 Jan 2014 15:17:54 -0600 Subject: [PATCH 020/254] Improve GeoIP City database support. When trying to open a city database, it now considers both the "REV0" and "REV1" versions of the city database instead of just the former. The extra fields of the "REV1" version (metro/area code) aren't yet put in geo_location records, this change just allows this version of the city database to be opened w/ same functionality as the other version. This should be convenient because libGeoIP expects either version to live at the same file system path, it's hard to tell which version you've got, and current free GeoLite databases seem to be "REV1". --- src/bro.bif | 80 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/src/bro.bif b/src/bro.bif index d789ef9f4e..e772b6eadf 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -3443,9 +3443,59 @@ static GeoIP* open_geoip_db(GeoIPDBTypes type) if ( GeoIP_db_avail(type) ) geoip = GeoIP_open_type(type, GEOIP_MEMORY_CACHE); + return geoip; + } + +static GeoIP* open_geoip_city_db() + { + GeoIP* geoip = open_geoip_db(GEOIP_CITY_EDITION_REV0); + if ( ! geoip ) - reporter->Info("Failed to open GeoIP database: %s", - GeoIPDBFileName[type]); + geoip = open_geoip_db(GEOIP_CITY_EDITION_REV1); + + if ( ! geoip ) + { + string rev0_path = GeoIPDBFileName[GEOIP_CITY_EDITION_REV0]; + string rev1_path = GeoIPDBFileName[GEOIP_CITY_EDITION_REV1]; + string db_path = rev0_path; + + // Maybe in the future the revisions won't share a common default path. + if ( rev0_path != rev1_path ) + db_path = rev0_path + " or " + rev1_path; + + reporter->Info("Failed to open GeoIP City database: %s", + db_path.c_str()); + } + + return geoip; + } + +static GeoIP* open_geoip_city_db_v6() + { + GeoIP* geoip = 0; + + // Both city edition revisions for IPv6 show up in libGeoIP 1.4.7. +#ifdef HAVE_GEOIP_CITY_EDITION_REV0_V6 + geoip = open_geoip_db(GEOIP_CITY_EDITION_REV0_V6); + + if ( ! geoip ) + geoip = open_geoip_db(GEOIP_CITY_EDITION_REV1_V6); + + if ( ! geoip ) + { + string rev0_path = GeoIPDBFileName[GEOIP_CITY_EDITION_REV0_V6]; + string rev1_path = GeoIPDBFileName[GEOIP_CITY_EDITION_REV1_V6]; + string db_path = rev0_path; + + // Maybe in the future the revisions won't share a common default path. + if ( rev0_path != rev1_path ) + db_path = rev0_path + " or " + rev1_path; + + reporter->Info("Failed to open GeoIP Cityv6 database: %s", + db_path.c_str()); + } +#endif + return geoip; } @@ -3476,31 +3526,41 @@ function lookup_location%(a: addr%) : geo_location if ( ! geoip_initialized ) { geoip_initialized = true; - geoip = open_geoip_db(GEOIP_CITY_EDITION_REV0); + geoip = open_geoip_city_db(); if ( ! geoip ) { geoip = open_geoip_db(GEOIP_COUNTRY_EDITION); + string db_path = GeoIPDBFileName[GEOIP_COUNTRY_EDITION]; + if ( ! geoip ) - builtin_error("Can't initialize GeoIP City/Country database"); + builtin_error(fmt("Failed fall back to GeoIP Country " + "database: %s", + GeoIPDBFileName[GEOIP_COUNTRY_EDITION])); else reporter->Info("Fell back to GeoIP Country database"); } else have_city_db = true; -#ifdef HAVE_GEOIP_CITY_EDITION_REV0_V6 - geoip_v6 = open_geoip_db(GEOIP_CITY_EDITION_REV0_V6); + geoip_v6 = open_geoip_city_db_v6(); + if ( geoip_v6 ) have_cityv6_db = true; -#endif #ifdef HAVE_GEOIP_COUNTRY_EDITION_V6 if ( ! geoip_v6 ) + { geoip_v6 = open_geoip_db(GEOIP_COUNTRY_EDITION_V6); + + if ( ! geoip_v6 ) + reporter->Info("Failed to open GeoIPv6 Country database: %s", + GeoIPDBFileName[GEOIP_COUNTRY_EDITION_V6]); + } #endif + if ( ! geoip_v6 ) - builtin_error("Can't initialize GeoIPv6 City/Country database"); + builtin_error("Can't open GeoIPv6 City/Country database"); } #ifdef HAVE_GEOIP_COUNTRY_EDITION_V6 @@ -3592,8 +3652,10 @@ function lookup_asn%(a: addr%) : count { geoip_asn_initialized = true; geoip_asn = open_geoip_db(GEOIP_ASNUM_EDITION); + if ( ! geoip_asn ) - builtin_error("Can't initialize GeoIP ASNUM database"); + builtin_error(fmt("Can't open GeoIP ASNUM database: %s", + GeoIPDBFileName[GEOIP_ASNUM_EDITION])); } if ( geoip_asn ) From 62527f643093955f0864161040d6be02a74716de Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 13 Jan 2014 02:02:37 -0800 Subject: [PATCH 021/254] Updating submodule(s). [nomail] --- aux/broctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/broctl b/aux/broctl index 2c6568efa9..477729c7e5 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit 2c6568efa970aee29d863cdf3662ff62fdaed4e6 +Subproject commit 477729c7e5053e662ab717a71c1a3eac3beb0c41 From 69ef268a4472f9dae1d50a39de38de934ef9cfb5 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 13 Jan 2014 09:16:51 -0800 Subject: [PATCH 022/254] Fixing compile problems with some versions of libc++. Reported by Craig Leres. --- CHANGES | 5 +++++ VERSION | 2 +- src/input/readers/Raw.cc | 2 +- src/input/readers/SQLite.cc | 2 +- src/logging/writers/SQLite.cc | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index fa65dff0a2..56710badf3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,9 @@ +2.2-93 | 2014-01-13 09:16:51 -0800 + + * Fixing compile problems with some versions of libc++. Reported by + Craig Leres. (Robin Sommer) + 2.2-91 | 2014-01-13 01:33:28 -0800 * Improve GeoIP City database support. When trying to open a city diff --git a/VERSION b/VERSION index 99a02e4a0e..dfb637a2d7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2-91 +2.2-93 diff --git a/src/input/readers/Raw.cc b/src/input/readers/Raw.cc index 0b69045fa0..53469335a2 100644 --- a/src/input/readers/Raw.cc +++ b/src/input/readers/Raw.cc @@ -365,7 +365,7 @@ bool Raw::DoInit(const ReaderInfo& info, int num_fields, const Field* const* fie fname = source.substr(0, fname.length() - 1); } - map::const_iterator it = info.config.find("stdin"); // data that is sent to the child process + ReaderInfo::config_map::const_iterator it = info.config.find("stdin"); // data that is sent to the child process if ( it != info.config.end() ) { stdin_string = it->second; diff --git a/src/input/readers/SQLite.cc b/src/input/readers/SQLite.cc index d02cc17fc7..794b8059ba 100644 --- a/src/input/readers/SQLite.cc +++ b/src/input/readers/SQLite.cc @@ -85,7 +85,7 @@ bool SQLite::DoInit(const ReaderInfo& info, int arg_num_fields, const threading: fullpath.append(".sqlite"); string query; - map::const_iterator it = info.config.find("query"); + ReaderInfo::config_map::const_iterator it = info.config.find("query"); if ( it == info.config.end() ) { Error(Fmt("No query specified when setting up SQLite data source. Aborting.", info.source)); diff --git a/src/logging/writers/SQLite.cc b/src/logging/writers/SQLite.cc index 46d1f17130..25f5cb012e 100644 --- a/src/logging/writers/SQLite.cc +++ b/src/logging/writers/SQLite.cc @@ -126,7 +126,7 @@ bool SQLite::DoInit(const WriterInfo& info, int arg_num_fields, fullpath.append(".sqlite"); string tablename; - map::const_iterator it = info.config.find("tablename"); + WriterInfo::config_map::const_iterator it = info.config.find("tablename"); if ( it == info.config.end() ) { MsgThread::Info(Fmt("tablename configuration option not found. Defaulting to path %s", info.path)); From 852af5d02e31d7361ede44cee3c8f93fea951ec6 Mon Sep 17 00:00:00 2001 From: Justin Azoff Date: Mon, 13 Jan 2014 16:55:07 -0500 Subject: [PATCH 023/254] Include file information in notices Add file_desc and file_mime_type information to notice output if it exists in the notice. --- scripts/base/frameworks/notice/main.bro | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/scripts/base/frameworks/notice/main.bro b/scripts/base/frameworks/notice/main.bro index a5f17a4979..328dea8e6a 100644 --- a/scripts/base/frameworks/notice/main.bro +++ b/scripts/base/frameworks/notice/main.bro @@ -400,11 +400,20 @@ function email_notice_to(n: Notice::Info, dest: string, extend: bool) # First off, finish the headers and include the human readable messages # then leave a blank line after the message. - email_text = string_cat(email_text, "\nMessage: ", n$msg); + email_text = string_cat(email_text, "\nMessage: ", n$msg, "\n"); if ( n?$sub ) - email_text = string_cat(email_text, "\nSub-message: ", n$sub); + email_text = string_cat(email_text, "Sub-message: ", n$sub, "\n"); - email_text = string_cat(email_text, "\n\n"); + email_text = string_cat(email_text, "\n"); + + # add information about the file if it exists + if (n?$file_desc) + email_text = string_cat(email_text, "File Description: ", n$file_desc, "\n"); + if (n?$file_mime_type) + email_text = string_cat(email_text, "File Mime Type: ", n$file_mime_type, "\n"); + + if (n?$file_desc || n?$file_mime_type) + email_text = string_cat(email_text, "\n"); # Next, add information about the connection if it exists. if ( n?$id ) From c48c5316299898d05533ee9f5b0273b575391a1f Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 15 Jan 2014 14:19:29 -0600 Subject: [PATCH 024/254] Integrate libmagic 5.16 via CMake ExternalProject. - Bumps CMake requirement to CMake 2.8. - Bro now always relies on builtin/shipped magic library/database. --- CMakeLists.txt | 33 ++++++++++++------ doc/install/install.rst | 18 ++++------ magic | 2 +- src/3rdparty | 2 +- src/CMakeLists.txt | 3 ++ src/util.cc | 34 ++++--------------- .../core.tunnels.gtp.outer_ip_frag/http.log | 2 +- .../bro..stdout | 2 +- .../b.out | 2 +- .../out | 2 +- 10 files changed, 45 insertions(+), 55 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 88cee2ec29..7feaa4d1aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ project(Bro C CXX) -cmake_minimum_required(VERSION 2.6.3 FATAL_ERROR) +cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR) include(cmake/CommonCMakeConfig.cmake) ######################################################################## @@ -39,6 +39,26 @@ set(VERSION_MAJ_MIN "${VERSION_MAJOR}.${VERSION_MINOR}") ######################################################################## ## Dependency Configuration +include(ExternalProject) + +set(LIBMAGIC_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libmagic-prefix) +set(LIBMAGIC_INCLUDE_DIR ${LIBMAGIC_PREFIX}/include) +set(LIBMAGIC_LIB_DIR ${LIBMAGIC_PREFIX}/lib) +set(LIBMAGIC_LIBRARY ${LIBMAGIC_LIB_DIR}/libmagic.a) +ExternalProject_Add(libmagic + PREFIX ${LIBMAGIC_PREFIX} + URL ${CMAKE_CURRENT_SOURCE_DIR}/src/3rdparty/file-5.16.tar.gz + CONFIGURE_COMMAND ./configure --enable-static --disable-shared + --prefix=${LIBMAGIC_PREFIX} + --includedir=${LIBMAGIC_INCLUDE_DIR} + --libdir=${LIBMAGIC_LIB_DIR} + BUILD_IN_SOURCE 1 + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 + LOG_INSTALL 1 +) + include(FindRequiredPackage) # Check cache value first to avoid displaying "Found sed" messages everytime @@ -57,7 +77,6 @@ FindRequiredPackage(BISON) FindRequiredPackage(PCAP) FindRequiredPackage(OpenSSL) FindRequiredPackage(BIND) -FindRequiredPackage(LibMagic) FindRequiredPackage(ZLIB) if (NOT BinPAC_ROOT_DIR AND @@ -73,18 +92,12 @@ if (MISSING_PREREQS) message(FATAL_ERROR "Configuration aborted due to missing prerequisites") endif () -set(libmagic_req 5.04) -if ( LibMagic_VERSION VERSION_LESS ${libmagic_req} ) - message(FATAL_ERROR "libmagic of at least version ${libmagic_req} required " - "(found ${LibMagic_VERSION})") -endif () - include_directories(BEFORE ${PCAP_INCLUDE_DIR} ${OpenSSL_INCLUDE_DIR} ${BIND_INCLUDE_DIR} ${BinPAC_INCLUDE_DIR} - ${LibMagic_INCLUDE_DIR} + ${LIBMAGIC_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ) @@ -163,7 +176,7 @@ set(brodeps ${PCAP_LIBRARY} ${OpenSSL_LIBRARIES} ${BIND_LIBRARY} - ${LibMagic_LIBRARY} + ${LIBMAGIC_LIBRARY} ${ZLIB_LIBRARY} ${OPTLIBS} ) diff --git a/doc/install/install.rst b/doc/install/install.rst index 7532a82cea..3678d948c2 100644 --- a/doc/install/install.rst +++ b/doc/install/install.rst @@ -29,14 +29,13 @@ before you begin: * Libpcap (http://www.tcpdump.org) * OpenSSL libraries (http://www.openssl.org) * BIND8 library - * Libmagic 5.04 or greater * Libz * Bash (for BroControl) * Python (for BroControl) To build Bro from source, the following additional dependencies are required: - * CMake 2.6.3 or greater (http://www.cmake.org) + * CMake 2.8.0 or greater (http://www.cmake.org) * Make * C/C++ compiler * SWIG (http://www.swig.org) @@ -44,7 +43,6 @@ To build Bro from source, the following additional dependencies are required: * Flex (Fast Lexical Analyzer) * Libpcap headers (http://www.tcpdump.org) * OpenSSL headers (http://www.openssl.org) - * libmagic headers * zlib headers * Perl @@ -55,13 +53,13 @@ that ``bash`` and ``python`` are in your ``PATH``): .. console:: - sudo yum install cmake make gcc gcc-c++ flex bison libpcap-devel openssl-devel python-devel swig zlib-devel file-devel + sudo yum install cmake make gcc gcc-c++ flex bison libpcap-devel openssl-devel python-devel swig zlib-devel * DEB/Debian-based Linux: .. console:: - sudo apt-get install cmake make gcc g++ flex bison libpcap-dev libssl-dev python-dev swig zlib1g-dev libmagic-dev + sudo apt-get install cmake make gcc g++ flex bison libpcap-dev libssl-dev python-dev swig zlib1g-dev * FreeBSD: @@ -78,15 +76,11 @@ that ``bash`` and ``python`` are in your ``PATH``): then going through its "Preferences..." -> "Downloads" menus to install the "Command Line Tools" component. - Lion (10.7) and Mountain Lion (10.8) come with all required - dependencies except for CMake_, SWIG_, and ``libmagic``. - + OS X comes with all required dependencies except for CMake_ and SWIG_. Distributions of these dependencies can likely be obtained from your preferred Mac OS X package management system (e.g. MacPorts_, Fink_, - or Homebrew_). - - Specifically for MacPorts, the ``cmake``, ``swig``, - ``swig-python`` and ``file`` packages provide the required dependencies. + or Homebrew_). Specifically for MacPorts, the ``cmake``, ``swig``, + ``swig-python`` and packages provide the required dependencies. Optional Dependencies diff --git a/magic b/magic index e87fe13a7b..a29b831d8e 160000 --- a/magic +++ b/magic @@ -1 +1 @@ -Subproject commit e87fe13a7b776182ffc8c75076d42702f5c28fed +Subproject commit a29b831d8ee63b7dbc64109e6dbd3f9aca6d5c82 diff --git a/src/3rdparty b/src/3rdparty index 12b5cb446c..5191111430 160000 --- a/src/3rdparty +++ b/src/3rdparty @@ -1 +1 @@ -Subproject commit 12b5cb446c8128bb22e5cbd7baa7d53669539487 +Subproject commit 51911114309cb9ac957502b412dc585e94e8fcbd diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8e22b504e4..c85b3b526f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -388,6 +388,9 @@ install(TARGETS bro DESTINATION bin) set(BRO_EXE bro CACHE STRING "Bro executable binary" FORCE) +# External libmagic project must be built before bro. +add_dependencies(bro libmagic) + # Target to create all the autogenerated files. add_custom_target(generate_outputs_stage1) add_dependencies(generate_outputs_stage1 ${bro_ALL_GENERATED_OUTPUTS}) diff --git a/src/util.cc b/src/util.cc index ad55e3f75e..5a0b55a34a 100644 --- a/src/util.cc +++ b/src/util.cc @@ -1649,48 +1649,28 @@ void operator delete[](void* v) #endif -// Being selective of which components of MAGIC_NO_CHECK_BUILTIN are actually -// known to be problematic, but keeping rest of libmagic's builtin checks. -#define DISABLE_LIBMAGIC_BUILTIN_CHECKS ( \ -/* MAGIC_NO_CHECK_COMPRESS | */ \ -/* MAGIC_NO_CHECK_TAR | */ \ -/* MAGIC_NO_CHECK_SOFT | */ \ -/* MAGIC_NO_CHECK_APPTYPE | */ \ -/* MAGIC_NO_CHECK_ELF | */ \ -/* MAGIC_NO_CHECK_TEXT | */ \ - MAGIC_NO_CHECK_CDF | \ - MAGIC_NO_CHECK_TOKENS \ -/* MAGIC_NO_CHECK_ENCODING */ \ -) - void bro_init_magic(magic_t* cookie_ptr, int flags) { if ( ! cookie_ptr || *cookie_ptr ) return; - *cookie_ptr = magic_open(flags|DISABLE_LIBMAGIC_BUILTIN_CHECKS); + *cookie_ptr = magic_open(flags); - // Use our custom database for mime types, but the default database - // from libmagic for the verbose file type. - const char* database = (flags & MAGIC_MIME) ? bro_magic_path() : 0; + // Always use Bro's custom magic database. + const char* database = bro_magic_path(); if ( ! *cookie_ptr ) { const char* err = magic_error(*cookie_ptr); - if ( ! err ) - err = "unknown"; - - reporter->InternalError("can't init libmagic: %s", err); + reporter->InternalError("can't init libmagic: %s", + err ? err : "unknown"); } else if ( magic_load(*cookie_ptr, database) < 0 ) { const char* err = magic_error(*cookie_ptr); - if ( ! err ) - err = "unknown"; - - const char* db_name = database ? database : ""; - reporter->InternalError("can't load magic file %s: %s", db_name, err); + reporter->InternalError("can't load magic file %s: %s", database, + err ? err : "unknown"); magic_close(*cookie_ptr); *cookie_ptr = 0; } diff --git a/testing/btest/Baseline/core.tunnels.gtp.outer_ip_frag/http.log b/testing/btest/Baseline/core.tunnels.gtp.outer_ip_frag/http.log index 20408a08fe..e312a8e6ba 100644 --- a/testing/btest/Baseline/core.tunnels.gtp.outer_ip_frag/http.log +++ b/testing/btest/Baseline/core.tunnels.gtp.outer_ip_frag/http.log @@ -6,5 +6,5 @@ #open 2013-08-26-19-02-18 #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth method host uri referrer user_agent request_body_len response_body_len status_code status_msg info_code info_msg filename tags username password proxied orig_fuids orig_mime_types resp_fuids resp_mime_types #types time string addr port addr port count string string string string string count count count string count string string table[enum] string string table[string] vector[string] vector[string] vector[string] vector[string] -1333458850.375568 CjhGID4nQcgTWjvg4c 10.131.47.185 1923 79.101.110.141 80 1 GET o-o.preferred.telekomrs-beg1.v2.lscache8.c.youtube.com /videoplayback?upn=MTU2MDY5NzQ5OTM0NTI3NDY4NDc&sparams=algorithm,burst,cp,factor,id,ip,ipbits,itag,source,upn,expire&fexp=912300,907210&algorithm=throttle-factor&itag=34&ip=212.0.0.0&burst=40&sver=3&signature=832FB1042E20780CFCA77A4DB5EA64AC593E8627.D1166C7E8365732E52DAFD68076DAE0146E0AE01&source=youtube&expire=1333484980&key=yt1&ipbits=8&factor=1.25&cp=U0hSSFRTUl9NSkNOMl9MTVZKOjh5eEN2SG8tZF84&id=ebf1e932d4bd1286&cm2=1 http://s.ytimg.com/yt/swfbin/watch_as3-vflqrJwOA.swf Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko; X-SBLSP) Chrome/17.0.963.83 Safari/535.11 0 56320 206 Partial Content - - - (empty) - - - - - FNJkBA1b8FSHt5N8jl application/octet-stream +1333458850.375568 CjhGID4nQcgTWjvg4c 10.131.47.185 1923 79.101.110.141 80 1 GET o-o.preferred.telekomrs-beg1.v2.lscache8.c.youtube.com /videoplayback?upn=MTU2MDY5NzQ5OTM0NTI3NDY4NDc&sparams=algorithm,burst,cp,factor,id,ip,ipbits,itag,source,upn,expire&fexp=912300,907210&algorithm=throttle-factor&itag=34&ip=212.0.0.0&burst=40&sver=3&signature=832FB1042E20780CFCA77A4DB5EA64AC593E8627.D1166C7E8365732E52DAFD68076DAE0146E0AE01&source=youtube&expire=1333484980&key=yt1&ipbits=8&factor=1.25&cp=U0hSSFRTUl9NSkNOMl9MTVZKOjh5eEN2SG8tZF84&id=ebf1e932d4bd1286&cm2=1 http://s.ytimg.com/yt/swfbin/watch_as3-vflqrJwOA.swf Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko; X-SBLSP) Chrome/17.0.963.83 Safari/535.11 0 56320 206 Partial Content - - - (empty) - - - - - FNJkBA1b8FSHt5N8jl binary #close 2013-08-26-19-02-18 diff --git a/testing/btest/Baseline/scripts.base.frameworks.file-analysis.bifs.set_timeout_interval/bro..stdout b/testing/btest/Baseline/scripts.base.frameworks.file-analysis.bifs.set_timeout_interval/bro..stdout index e78f5c8c17..1cce5e77f0 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.file-analysis.bifs.set_timeout_interval/bro..stdout +++ b/testing/btest/Baseline/scripts.base.frameworks.file-analysis.bifs.set_timeout_interval/bro..stdout @@ -11,7 +11,7 @@ source: HTTP FILE_NEW file #1, 0, 0 MIME_TYPE -application/octet-stream +binary FILE_OVER_NEW_CONNECTION FILE_TIMEOUT FILE_TIMEOUT diff --git a/testing/btest/Baseline/scripts.base.frameworks.file-analysis.http.partial-content/b.out b/testing/btest/Baseline/scripts.base.frameworks.file-analysis.http.partial-content/b.out index 9c05f311f3..306fa3493c 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.file-analysis.http.partial-content/b.out +++ b/testing/btest/Baseline/scripts.base.frameworks.file-analysis.http.partial-content/b.out @@ -11,7 +11,7 @@ source: HTTP FILE_NEW file #1, 0, 0 MIME_TYPE -application/octet-stream +binary FILE_OVER_NEW_CONNECTION FILE_TIMEOUT FILE_STATE_REMOVE diff --git a/testing/btest/Baseline/scripts.base.frameworks.file-analysis.irc/out b/testing/btest/Baseline/scripts.base.frameworks.file-analysis.irc/out index fcd30b2253..2fde3f5073 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.file-analysis.irc/out +++ b/testing/btest/Baseline/scripts.base.frameworks.file-analysis.irc/out @@ -10,7 +10,7 @@ file #1, 0, 0 FILE_BOF_BUFFER \0\0^Ex\0\0^J\xf0\0\0^P MIME_TYPE -application/octet-stream +binary FILE_OVER_NEW_CONNECTION FILE_STATE_REMOVE file #1, 124, 0 From 0c7ffe74ee9515e7ce4a1c867a260d254786cc3f Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 15 Jan 2014 15:42:18 -0600 Subject: [PATCH 025/254] Don't use LOG_* options to ExternalProject_Add if not supported. They're in CMake 2.8.3 and greater, but not strictly necessary for the build to work -- they just make build output a bit nicer. --- CMakeLists.txt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7feaa4d1aa..28027d63d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,15 @@ set(VERSION_MAJ_MIN "${VERSION_MAJOR}.${VERSION_MINOR}") include(ExternalProject) +# LOG_* options to ExternalProject_Add appear in CMake 2.8.3. If +# available, using them hides external project configure/build output. +if("${CMAKE_VERSION}" VERSION_GREATER 2.8.2) + set(EXTERNAL_PROJECT_LOG_OPTIONS + LOG_DOWNLOAD 1 LOG_UPDATE 1 LOG_CONFIGURE 1 LOG_BUILD 1 LOG_INSTALL 1) +else() + set(EXTERNAL_PROJECT_LOG_OPTIONS) +endif() + set(LIBMAGIC_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libmagic-prefix) set(LIBMAGIC_INCLUDE_DIR ${LIBMAGIC_PREFIX}/include) set(LIBMAGIC_LIB_DIR ${LIBMAGIC_PREFIX}/lib) @@ -53,10 +62,7 @@ ExternalProject_Add(libmagic --includedir=${LIBMAGIC_INCLUDE_DIR} --libdir=${LIBMAGIC_LIB_DIR} BUILD_IN_SOURCE 1 - LOG_DOWNLOAD 1 - LOG_CONFIGURE 1 - LOG_BUILD 1 - LOG_INSTALL 1 + ${EXTERNAL_PROJECT_LOG_OPTIONS} ) include(FindRequiredPackage) From 7717a3eb674f07ae7a1920b829dcfbcfeacbd257 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 16 Jan 2014 16:03:04 -0600 Subject: [PATCH 026/254] BIT-867 - Support GRE tunnel decapsulation. This includes enhanced GRE headers. GRE tunnels are treated just like IP-in-IP tunnels by parsing past the GRE header in between the delivery and payload IP packets. --- scripts/base/init-bare.bro | 6 +- src/Sessions.cc | 123 ++++++++++++++++++ src/const.bif | 1 + .../Baseline/core.tunnels.gre-in-gre/conn.log | 12 ++ .../core.tunnels.gre-in-gre/tunnel.log | 11 ++ .../btest/Baseline/core.tunnels.gre/conn.log | 16 +++ .../btest/Baseline/core.tunnels.gre/dns.log | 11 ++ .../btest/Baseline/core.tunnels.gre/ssh.log | 10 ++ .../Baseline/core.tunnels.gre/tunnel.log | 10 ++ testing/btest/Traces/tunnels/gre-sample.pcap | Bin 0 -> 7395 bytes .../btest/Traces/tunnels/gre-within-gre.pcap | Bin 0 -> 111736 bytes testing/btest/core/tunnels/gre-in-gre.test | 3 + testing/btest/core/tunnels/gre.test | 5 + 13 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 testing/btest/Baseline/core.tunnels.gre-in-gre/conn.log create mode 100644 testing/btest/Baseline/core.tunnels.gre-in-gre/tunnel.log create mode 100644 testing/btest/Baseline/core.tunnels.gre/conn.log create mode 100644 testing/btest/Baseline/core.tunnels.gre/dns.log create mode 100644 testing/btest/Baseline/core.tunnels.gre/ssh.log create mode 100644 testing/btest/Baseline/core.tunnels.gre/tunnel.log create mode 100644 testing/btest/Traces/tunnels/gre-sample.pcap create mode 100644 testing/btest/Traces/tunnels/gre-within-gre.pcap create mode 100644 testing/btest/core/tunnels/gre-in-gre.test create mode 100644 testing/btest/core/tunnels/gre.test diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 9f8c9f42ac..8d4899b785 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -3057,6 +3057,9 @@ export { ## Toggle whether to do GTPv1 decapsulation. const enable_gtpv1 = T &redef; + ## Toggle whether to do GRE decapsulation. + const enable_gre = T &redef; + ## With this option set, the Teredo analysis will first check to see if ## other protocol analyzers have confirmed that they think they're ## parsing the right protocol and only continue with Teredo tunnel @@ -3082,7 +3085,8 @@ export { ## may work better. const delay_gtp_confirmation = F &redef; - ## How often to cleanup internal state for inactive IP tunnels. + ## How often to cleanup internal state for inactive IP tunnels + ## (includes GRE tunnels). const ip_tunnel_timeout = 24hrs &redef; } # end export module GLOBAL; diff --git a/src/Sessions.cc b/src/Sessions.cc index 7d497adf77..cc5e48a9b5 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -376,6 +376,31 @@ int NetSessions::CheckConnectionTag(Connection* conn) return 1; } +static unsigned int gre_header_len(uint16 flags) + { + unsigned int len = 4; // Always has 2 byte flags and 2 byte protocol type. + + if ( flags & 0x8000 ) + // Checksum/Reserved1 present. + len += 4; + + // Not considering routing presence bit since it's deprecated... + + if ( flags & 0x2000 ) + // Key present. + len += 4; + + if ( flags & 0x1000 ) + // Sequence present. + len += 4; + + if ( flags & 0x0080 ) + // Acknowledgement present. + len += 4; + + return len; + } + void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, const IP_Hdr* ip_hdr, const u_char* const pkt, int hdr_size, const EncapsulationStack* encapsulation) @@ -562,6 +587,101 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, break; } + case IPPROTO_GRE: + { + if ( ! BifConst::Tunnel::enable_gre ) + { + Weird("GRE_tunnel", ip_hdr, encapsulation); + Remove(f); + return; + } + + uint16 flags_ver = ntohs(*((uint16*)(data + 0))); + uint16 proto_typ = ntohs(*((uint16*)(data + 2))); + int gre_version = flags_ver & 0x0007; + + if ( gre_version != 0 && gre_version != 1 ) + { + Weird(fmt("unknown_gre_version_%d", gre_version), ip_hdr, + encapsulation); + Remove(f); + return; + } + + if ( gre_version == 0 ) + { + if ( proto_typ != 0x0800 && proto_typ != 0x86dd ) + { + // Not IPv4/IPv6 payload. + Weird(fmt("unknown_gre_protocol_%"PRIu16, proto_typ), ip_hdr, + encapsulation); + Remove(f); + return; + } + + proto = (proto_typ == 0x0800) ? IPPROTO_IPV4 : IPPROTO_IPV6; + } + else // gre_version == 1 + { + if ( proto_typ != 0x880b) + { + // Enhanced GRE payload must be PPP. + Weird("egre_protocol_type", ip_hdr, encapsulation); + Remove(f); + return; + } + } + + if ( flags_ver & 0x4000 ) + { + // RFC 2784 deprecates the variable length routing field + // specified by RFC 1701. It could be parsed here, but easiest + // to just skip for now. + Weird("gre_routing", ip_hdr, encapsulation); + Remove(f); + return; + } + + if ( flags_ver & 0x0078 ) + { + // Expect last 4 bits of flags are reserved, undefined. + Weird("unknown_gre_flags", ip_hdr, encapsulation); + Remove(f); + return; + } + + unsigned int gre_len = gre_header_len(flags_ver); + unsigned int ppp_len = gre_version == 1 ? 1 : 0; + + if ( len < gre_len + ppp_len || caplen < gre_len + ppp_len ) + { + Weird("truncated_GRE", ip_hdr, encapsulation); + Remove(f); + return; + } + + if ( gre_version == 1 ) + { + int ppp_proto = *((uint8*)(data + gre_len)); + + if ( ppp_proto != 0x0021 && ppp_proto != 0x0057 ) + { + Weird("non_ip_packet_in_egre", ip_hdr, encapsulation); + Remove(f); + return; + } + + proto = (ppp_proto == 0x0021) ? IPPROTO_IPV4 : IPPROTO_IPV6; + } + + data += gre_len + ppp_len; + len -= gre_len + ppp_len; + caplen -= gre_len + ppp_len; + + // Treat GRE tunnel like IP tunnels, fallthrough to logic below now + // that GRE header is stripped and only payload packet remains. + } + case IPPROTO_IPV4: case IPPROTO_IPV6: { @@ -822,6 +942,9 @@ bool NetSessions::CheckHeaderTrunc(int proto, uint32 len, uint32 caplen, case IPPROTO_NONE: min_hdr_len = 0; break; + case IPPROTO_GRE: + min_hdr_len = 4; + break; case IPPROTO_ICMP: case IPPROTO_ICMPV6: default: diff --git a/src/const.bif b/src/const.bif index a45dfb0a7a..fd0419c7d9 100644 --- a/src/const.bif +++ b/src/const.bif @@ -17,6 +17,7 @@ const Tunnel::enable_ip: bool; const Tunnel::enable_ayiya: bool; const Tunnel::enable_teredo: bool; const Tunnel::enable_gtpv1: bool; +const Tunnel::enable_gre: bool; const Tunnel::yielding_teredo_decapsulation: bool; const Tunnel::delay_teredo_confirmation: bool; const Tunnel::delay_gtp_confirmation: bool; diff --git a/testing/btest/Baseline/core.tunnels.gre-in-gre/conn.log b/testing/btest/Baseline/core.tunnels.gre-in-gre/conn.log new file mode 100644 index 0000000000..6da1bd2132 --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre-in-gre/conn.log @@ -0,0 +1,12 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open 2014-01-16-21-51-36 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string bool count string count count count count table[string] +1341436440.002928 CRJuHdVW0XPVINV8a 3.3.3.2 520 224.0.0.9 520 udp - 26.148268 48 0 S0 - 0 D 2 104 0 0 CjhGID4nQcgTWjvg4c +1341436424.378840 CsRx2w45OKnoww6xl4 3.3.3.1 520 224.0.0.9 520 udp - 28.555457 168 0 S0 - 0 D 2 224 0 0 CjhGID4nQcgTWjvg4c +1341436424.204043 CCvvfg3TEfuqmmG4bh 10.10.25.1 8 192.168.1.2 0 icmp - 42.380221 22464 22464 OTH - 0 - 312 31200 312 31200 CjhGID4nQcgTWjvg4c +#close 2014-01-16-21-51-36 diff --git a/testing/btest/Baseline/core.tunnels.gre-in-gre/tunnel.log b/testing/btest/Baseline/core.tunnels.gre-in-gre/tunnel.log new file mode 100644 index 0000000000..277d1df679 --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre-in-gre/tunnel.log @@ -0,0 +1,11 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path tunnel +#open 2014-01-16-21-51-36 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p tunnel_type action +#types time string addr port addr port enum enum +1341436424.204043 CXWv6p3arKYeMETxOg 72.205.54.70 0 86.106.164.150 0 Tunnel::IP Tunnel::DISCOVER +1341436424.204043 CjhGID4nQcgTWjvg4c 10.10.11.2 0 10.10.13.2 0 Tunnel::IP Tunnel::DISCOVER +#close 2014-01-16-21-51-36 diff --git a/testing/btest/Baseline/core.tunnels.gre/conn.log b/testing/btest/Baseline/core.tunnels.gre/conn.log new file mode 100644 index 0000000000..b29d87f40a --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre/conn.log @@ -0,0 +1,16 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open 2014-01-16-21-51-12 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string bool count string count count count count table[string] +1055289978.756932 CsRx2w45OKnoww6xl4 66.59.111.190 40264 172.28.2.3 22 tcp ssh 3.157831 952 1671 SF - 0 ShAdDaFf 12 1584 10 2199 CXWv6p3arKYeMETxOg +1055289987.055189 CRJuHdVW0XPVINV8a 66.59.111.190 37675 172.28.2.3 53 udp dns 5.001141 66 0 S0 - 0 D 2 122 0 0 CXWv6p3arKYeMETxOg +1055289996.849099 CIPOse170MGiRM1Qf4 66.59.111.190 123 129.170.17.4 123 udp - 0.072374 48 48 SF - 0 Dd 1 76 1 76 CXWv6p3arKYeMETxOg +1055289973.849878 CCvvfg3TEfuqmmG4bh 66.59.111.190 123 18.26.4.105 123 udp - 0.074086 48 48 SF - 0 Dd 1 76 1 76 CXWv6p3arKYeMETxOg +1055289992.849231 C6pKV8GSxOnSLghOa 66.59.111.190 123 66.59.111.182 123 udp - 0.056629 48 48 SF - 0 Dd 1 76 1 76 CXWv6p3arKYeMETxOg +1055289968.793044 CjhGID4nQcgTWjvg4c 66.59.111.190 8 172.28.2.3 0 icmp - 3.061298 224 224 OTH - 0 - 4 336 4 336 CXWv6p3arKYeMETxOg +1055289987.106744 CPbrpk1qSsw6ESzHV4 172.28.2.3 3 66.59.111.190 3 icmp - 4.994662 122 0 OTH - 0 - 2 178 0 0 CXWv6p3arKYeMETxOg +#close 2014-01-16-21-51-12 diff --git a/testing/btest/Baseline/core.tunnels.gre/dns.log b/testing/btest/Baseline/core.tunnels.gre/dns.log new file mode 100644 index 0000000000..2b8b9fc6ab --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre/dns.log @@ -0,0 +1,11 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path dns +#open 2014-01-16-21-51-12 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto trans_id query qclass qclass_name qtype qtype_name rcode rcode_name AA TC RD RA Z answers TTLs rejected +#types time string addr port addr port enum count string count string count string count string bool bool bool bool count vector[string] vector[interval] bool +1055289987.055189 CRJuHdVW0XPVINV8a 66.59.111.190 37675 172.28.2.3 53 udp 48554 www.gleeble.org 1 C_INTERNET 255 * - - F F T F 0 - - F +1055289992.056330 CRJuHdVW0XPVINV8a 66.59.111.190 37675 172.28.2.3 53 udp 48554 www.gleeble.org 1 C_INTERNET 255 * - - F F T F 0 - - F +#close 2014-01-16-21-51-12 diff --git a/testing/btest/Baseline/core.tunnels.gre/ssh.log b/testing/btest/Baseline/core.tunnels.gre/ssh.log new file mode 100644 index 0000000000..5b05545bd0 --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre/ssh.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ssh +#open 2014-01-16-21-51-12 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p status direction client server +#types time string addr port addr port string enum string string +1055289978.855137 CsRx2w45OKnoww6xl4 66.59.111.190 40264 172.28.2.3 22 failure INBOUND SSH-2.0-OpenSSH_3.6.1p1 SSH-1.99-OpenSSH_3.1p1 +#close 2014-01-16-21-51-12 diff --git a/testing/btest/Baseline/core.tunnels.gre/tunnel.log b/testing/btest/Baseline/core.tunnels.gre/tunnel.log new file mode 100644 index 0000000000..f0d87f4964 --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre/tunnel.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path tunnel +#open 2014-01-16-21-51-12 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p tunnel_type action +#types time string addr port addr port enum enum +1055289968.793044 CXWv6p3arKYeMETxOg 172.27.1.66 0 66.59.109.137 0 Tunnel::IP Tunnel::DISCOVER +#close 2014-01-16-21-51-12 diff --git a/testing/btest/Traces/tunnels/gre-sample.pcap b/testing/btest/Traces/tunnels/gre-sample.pcap new file mode 100644 index 0000000000000000000000000000000000000000..31c08b6ba4761ebcb5fe702c9854a43d2e586b62 GIT binary patch literal 7395 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 Ezmr7m6951J literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/tunnels/gre-within-gre.pcap b/testing/btest/Traces/tunnels/gre-within-gre.pcap new file mode 100644 index 0000000000000000000000000000000000000000..c0a8d5c41beb6962fbc3ee638815cf2b166521d1 GIT binary patch literal 111736 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 E0q`ViQ2+n{ literal 0 HcmV?d00001 diff --git a/testing/btest/core/tunnels/gre-in-gre.test b/testing/btest/core/tunnels/gre-in-gre.test new file mode 100644 index 0000000000..ce85f54dbb --- /dev/null +++ b/testing/btest/core/tunnels/gre-in-gre.test @@ -0,0 +1,3 @@ +# @TEST-EXEC: bro -r $TRACES/tunnels/gre-within-gre.pcap +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff tunnel.log diff --git a/testing/btest/core/tunnels/gre.test b/testing/btest/core/tunnels/gre.test new file mode 100644 index 0000000000..0ce9a0c8b8 --- /dev/null +++ b/testing/btest/core/tunnels/gre.test @@ -0,0 +1,5 @@ +# @TEST-EXEC: bro -r $TRACES/tunnels/gre-sample.pcap +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff tunnel.log +# @TEST-EXEC: btest-diff dns.log +# @TEST-EXEC: btest-diff ssh.log From 4901032660167a156261c6b0d5023c6fe19680a1 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 16 Jan 2014 16:40:23 -0600 Subject: [PATCH 027/254] Simplify FragReassembler memory management. --- src/Sessions.cc | 26 +++----------------------- src/Sessions.h | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/Sessions.cc b/src/Sessions.cc index cc5e48a9b5..f4131d6a10 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -471,6 +471,8 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, } } + FragReassemblerTracker frt(this, f); + len -= ip_hdr_len; // remove IP header caplen -= ip_hdr_len; @@ -485,7 +487,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, vl->append(ip_hdr->BuildPktHdrVal()); mgr.QueueEvent(esp_packet, vl); } - Remove(f); + // Can't do more since upper-layer payloads are going to be encrypted. return; } @@ -500,7 +502,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ! ignore_checksums && mobility_header_checksum(ip_hdr) != 0xffff ) { Weird("bad_MH_checksum", hdr, pkt, encapsulation); - Remove(f); return; } @@ -514,7 +515,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ip_hdr->NextProto() != IPPROTO_NONE ) Weird("mobility_piggyback", hdr, pkt, encapsulation); - Remove(f); return; } #endif @@ -522,10 +522,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, int proto = ip_hdr->NextProto(); if ( CheckHeaderTrunc(proto, len, caplen, hdr, pkt, encapsulation) ) - { - Remove(f); return; - } const u_char* data = ip_hdr->Payload(); @@ -592,7 +589,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ! BifConst::Tunnel::enable_gre ) { Weird("GRE_tunnel", ip_hdr, encapsulation); - Remove(f); return; } @@ -604,7 +600,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, { Weird(fmt("unknown_gre_version_%d", gre_version), ip_hdr, encapsulation); - Remove(f); return; } @@ -615,7 +610,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, // Not IPv4/IPv6 payload. Weird(fmt("unknown_gre_protocol_%"PRIu16, proto_typ), ip_hdr, encapsulation); - Remove(f); return; } @@ -627,7 +621,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, { // Enhanced GRE payload must be PPP. Weird("egre_protocol_type", ip_hdr, encapsulation); - Remove(f); return; } } @@ -638,7 +631,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, // specified by RFC 1701. It could be parsed here, but easiest // to just skip for now. Weird("gre_routing", ip_hdr, encapsulation); - Remove(f); return; } @@ -646,7 +638,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, { // Expect last 4 bits of flags are reserved, undefined. Weird("unknown_gre_flags", ip_hdr, encapsulation); - Remove(f); return; } @@ -656,7 +647,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( len < gre_len + ppp_len || caplen < gre_len + ppp_len ) { Weird("truncated_GRE", ip_hdr, encapsulation); - Remove(f); return; } @@ -667,7 +657,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ppp_proto != 0x0021 && ppp_proto != 0x0057 ) { Weird("non_ip_packet_in_egre", ip_hdr, encapsulation); - Remove(f); return; } @@ -688,7 +677,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ! BifConst::Tunnel::enable_ip ) { Weird("IP_tunnel", ip_hdr, encapsulation); - Remove(f); return; } @@ -696,7 +684,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, encapsulation->Depth() >= BifConst::Tunnel::max_depth ) { Weird("exceeded_tunnel_max_depth", ip_hdr, encapsulation); - Remove(f); return; } @@ -713,7 +700,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( result != 0 ) { delete inner; - Remove(f); return; } @@ -740,7 +726,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, DoNextInnerPacket(t, hdr, inner, encapsulation, ip_tunnels[tunnel_idx].first); - Remove(f); return; } @@ -753,13 +738,11 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, encapsulation->LastType() == BifEnum::Tunnel::TEREDO ) ) Weird("ipv6_no_next", hdr, pkt); - Remove(f); return; } default: Weird(fmt("unknown_protocol_%d", proto), hdr, pkt, encapsulation); - Remove(f); return; } @@ -785,7 +768,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( consistent < 0 ) { delete h; - Remove(f); return; } @@ -809,7 +791,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, if ( ! conn ) { delete h; - Remove(f); return; } @@ -841,7 +822,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, { // Above we already recorded the fragment in its entirety. f->DeleteTimer(); - Remove(f); } else if ( record_packet ) diff --git a/src/Sessions.h b/src/Sessions.h index 1788541f45..e2dec3b1aa 100644 --- a/src/Sessions.h +++ b/src/Sessions.h @@ -286,6 +286,21 @@ protected: NetSessions::IPPair tunnel_idx; }; + +class FragReassemblerTracker { +public: + FragReassemblerTracker(NetSessions* s, FragReassembler* f) + : net_sessions(s), frag_reassembler(f) + { } + + ~FragReassemblerTracker() + { net_sessions->Remove(frag_reassembler); } + +private: + NetSessions* net_sessions; + FragReassembler* frag_reassembler; +}; + // Manager for the currently active sessions. extern NetSessions* sessions; From dca81174e5d8d8315cf75580842832324ee1cbd1 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 20 Jan 2014 12:49:09 -0800 Subject: [PATCH 028/254] Updating submodule(s). [nomail] --- aux/broctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/broctl b/aux/broctl index 0ae6d9c9e0..08f4987e5d 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit 0ae6d9c9e06a804918c3e0459144fd00b1ea82df +Subproject commit 08f4987e5d13c004ea1433759224aef39ca16439 From b9bab8e4b4b3ef226969826b925da2626bffe172 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 20 Jan 2014 14:29:26 -0800 Subject: [PATCH 029/254] Updating submodule(s). [nomail] --- aux/broctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/broctl b/aux/broctl index 08f4987e5d..ae4296feda 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit 08f4987e5d13c004ea1433759224aef39ca16439 +Subproject commit ae4296feda50bf84fdd0a2754a0e536d535a28ed From b8274e0d445a7699fa49af76f01714e875b86410 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Tue, 21 Jan 2014 07:12:59 -0800 Subject: [PATCH 030/254] Updating submodule(s). [nomail] --- aux/broctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/broctl b/aux/broctl index ae4296feda..e4b8472f30 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit ae4296feda50bf84fdd0a2754a0e536d535a28ed +Subproject commit e4b8472f3050f385f722c23544493ff568b4472c From 430cf311e995f8ea257aaccab7db366b43ebf1de Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Tue, 21 Jan 2014 07:14:03 -0800 Subject: [PATCH 031/254] Updating submodule(s). [nomail] --- aux/broctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/broctl b/aux/broctl index e4b8472f30..c1b8087220 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit e4b8472f3050f385f722c23544493ff568b4472c +Subproject commit c1b808722048443f909fea26898ea0e308e28c95 From e88ac7221dbd89c32b05e1ab247e95651a7ae661 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 21 Jan 2014 11:32:55 -0600 Subject: [PATCH 032/254] Pass over doc xref links and linking style. --- doc/broids/index.rst | 14 +++++--------- doc/frameworks/file-analysis.rst | 3 +++ doc/frameworks/notice.rst | 2 ++ doc/frameworks/sumstats.rst | 3 +++ doc/httpmonitor/index.rst | 10 +++++----- doc/index.rst | 2 -- doc/logs/index.rst | 18 ++++-------------- doc/mimestats/index.rst | 7 +++---- 8 files changed, 25 insertions(+), 34 deletions(-) diff --git a/doc/broids/index.rst b/doc/broids/index.rst index dd0a0e8b22..1d5f63ec7f 100644 --- a/doc/broids/index.rst +++ b/doc/broids/index.rst @@ -1,8 +1,3 @@ -__ http://www.bro.org/sphinx-git/scripts/base/protocols/ftp/main.bro.html#id-FTP::parse_ftp_reply_code -__ http://www.bro.org/sphinx-git/frameworks/sumstats.html -__ http://www.bro.org/sphinx-git/frameworks/notice.html -__ http://www.bro.org/sphinx-git/_downloads/detect-bruteforcing.bro -__ http://www.bro.org/sphinx-git/scripts/policy/frameworks/files/detect-MHR.bro.html .. _bro-ids: @@ -34,7 +29,8 @@ We start by defining a threshold for the number of attempts and a monitoring int const bruteforce_measurement_interval = 15mins &redef; } -Now, using the ftp_reply event, we check for error codes from the `500 series `_ for the "USER" and "PASS" commands, representing rejected usernames or passwords. For this, we can use the `FTP::parse_ftp_reply`__ function to break down the reply code and check if the first digit is a "5" or not. If true, we then use the `SumStats`__ framework to keep track of the number of failed attempts. +Now, using the ftp_reply event, we check for error codes from the `500 series `_ for the "USER" and "PASS" commands, representing rejected usernames or passwords. For this, we can use the :bro:see:`FTP::parse_ftp_reply_code` function to break down the reply code and check if the first digit is a "5" or not. If true, we then use the +:ref:`Summary Statistics Framework ` to keep track of the number of failed attempts. .. code:: bro @@ -73,7 +69,7 @@ exceeds the specified threshold during the measuring interval. }]); } -Printing a message on the console is a good start but it will be better if we raise an alarm instead using the `Notice`__ framework. For this, we need to define a new Notice type and trigger the alarm under the right +Printing a message on the console is a good start but it will be better if we raise an alarm instead using the :ref:`Notice Framework `. For this, we need to define a new Notice type and trigger the alarm under the right conditions. Below is the final code for our script. .. code:: bro @@ -139,7 +135,7 @@ conditions. Below is the final code for our script. } } -As a final note, the `detect-bruteforcing.bro`__ script above is include with Bro out of the box, so you only need to load it at startup to instruct Bro to detect and notify of FTP bruteforce attacks. +As a final note, the :doc:`detect-bruteforcing.bro ` script above is include with Bro out of the box, so you only need to load it at startup to instruct Bro to detect and notify of FTP bruteforce attacks. ------------- Other Attacks @@ -150,6 +146,6 @@ Checking files against known malware hashes ------------------------------------------- Files transmitted on your network could either be completely harmless or contain viruses and other threats. One possible action against this threat is to compute the hashes of the files and compare them against a list of known malware hashes. Bro simplifies this task -by offering a `detect-MHR.bro`__ script that creates and compares +by offering a :doc:`detect-MHR.bro ` script that creates and compares hashes against the `Malware Hash Registry `_ maintained by Team Cymru. You only need to load this script along with your other scripts at startup time. diff --git a/doc/frameworks/file-analysis.rst b/doc/frameworks/file-analysis.rst index 50fb89317c..e70b124af7 100644 --- a/doc/frameworks/file-analysis.rst +++ b/doc/frameworks/file-analysis.rst @@ -1,3 +1,6 @@ + +.. _file-analysis-framework: + ============= File Analysis ============= diff --git a/doc/frameworks/notice.rst b/doc/frameworks/notice.rst index fe94d7f2ca..2c20149ce5 100644 --- a/doc/frameworks/notice.rst +++ b/doc/frameworks/notice.rst @@ -1,4 +1,6 @@ +.. _notice-framework: + Notice Framework ================ diff --git a/doc/frameworks/sumstats.rst b/doc/frameworks/sumstats.rst index 6ab2f43b35..aaed35be29 100644 --- a/doc/frameworks/sumstats.rst +++ b/doc/frameworks/sumstats.rst @@ -1,3 +1,6 @@ + +.. _sumstats-framework: + ================== Summary Statistics ================== diff --git a/doc/httpmonitor/index.rst b/doc/httpmonitor/index.rst index 41f9dd955c..9b640c63ec 100644 --- a/doc/httpmonitor/index.rst +++ b/doc/httpmonitor/index.rst @@ -1,5 +1,3 @@ -__ http://www.bro.org/sphinx-git/scripts/base/protocols/http/main.bro.html -__ http://www.bro.org/sphinx-git/frameworks/file-analysis.html .. _http-monitor: @@ -43,7 +41,8 @@ point, we would like to stress out the fact that there is no just one right way depend on the expertise of the person doing the analysis and the specific details of the task to accomplish. For more information about how to handle the HTTP protocol in Bro, including a complete list -of the fields available in http.log, go to Bro's HTTP reference `page`__. +of the fields available in http.log, go to Bro's +:doc:`HTTP script reference `. ------------------------ Detecting a Proxy Server @@ -219,8 +218,9 @@ Inspecting Files Files are often transmitted on regular HTTP conversations between a client and a server. Most of the time these files are harmless, just images and some other multimedia content, but there are also types of files, specially executable files, that can damage -your system. We can instruct Bro to create a copy of all executable files that it sees for later analysis using the `File Analysis -Framework`__ (introduced with Bro 2.2) as shown in the following script. +your system. We can instruct Bro to create a copy of all executable files that it sees for later analysis using the +:ref:`File Analysis Framework ` +(introduced with Bro 2.2) as shown in the following script. .. code:: bro diff --git a/doc/index.rst b/doc/index.rst index 98006034c2..3da35e7b7a 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -44,8 +44,6 @@ Reference Section .. -* `Notice Index `_ (TODO: Move to reference - section, but can't figure out how to include it into toctree) * :ref:`General Index ` * :ref:`search` diff --git a/doc/logs/index.rst b/doc/logs/index.rst index a6844d6e03..b71546db72 100644 --- a/doc/logs/index.rst +++ b/doc/logs/index.rst @@ -1,19 +1,9 @@ -__ http://www.bro.org/sphinx-git/scripts/base/protocols/http/main.bro.html#type-HTTP::Info -__ http://www.bro.org/sphinx-git/scripts/base/protocols/ftp/info.bro.html#type-FTP::Info -__ http://www.bro.org/sphinx-git/scripts/base/protocols/ssl/main.bro.html#type-SSL::Info -__ http://www.bro.org/sphinx-git/scripts/policy/protocols/ssl/known-certs.bro.html#type-Known::CertsInfo -__ http://www.bro.org/sphinx-git/scripts/base/protocols/smtp/main.bro.html#type-SMTP::Info -__ http://www.bro.org/sphinx-git/scripts/base/protocols/dns/main.bro.html#type-DNS::Info -__ http://www.bro.org/sphinx-git/scripts/base/protocols/conn/main.bro.html#type-Conn::Info -__ http://www.bro.org/sphinx-git/scripts/base/frameworks/dpd/main.bro.html#type-DPD::Info -__ http://www.bro.org/sphinx-git/scripts/base/frameworks/files/main.bro.html#type-Files::Info -__ http://www.bro.org/sphinx-git/scripts/base/frameworks/notice/weird.bro.html#type-Weird::Info -.. _using-bro: +.. _bro-logging: -========= -Using Bro -========= +=========== +Bro Logging +=========== .. contents:: diff --git a/doc/mimestats/index.rst b/doc/mimestats/index.rst index 903131acd5..88499a5d6e 100644 --- a/doc/mimestats/index.rst +++ b/doc/mimestats/index.rst @@ -1,4 +1,3 @@ -__ http://www.bro.org/sphinx-git/frameworks/sumstats.html .. _mime-stats: @@ -12,17 +11,17 @@ non-text attachments on email, it is also used by Web browser to identify the ty In this tutorial, we will show how to use the Sumstats Framework to collect some statistics information based on MIME types, specifically the total number of occurrences, size in bytes, and number of unique hosts transmitting files over HTTP per each type. For instructions about extracting and creating a local copy -of these files, visit `this <../httpmonitor/index.html#inspecting-files>`_ tutorial instead. +of these files, visit :ref:`this ` tutorial instead. ------------------------------------------------ MIME Statistics with Sumstats ------------------------------------------------ -When working with the `Sumstats`__ framework, you need to define three different pieces: (i) Observations, where +When working with the :ref:`Summary Statistics Framework `, you need to define three different pieces: (i) Observations, where the event is observed and fed into the framework. (ii) Reducers, where observations are collected and measured. (iii) Sumstats, where the main functionality is implemented. So, we start by defining our observation along with a record to store all statistics values and an observation interval. We are conducting our observation on -the `HTTP::log_http` event and we are interested in the MIME type, size of the file ("response_body_len") and the originator host ("orig_h"). We use the MIME +the :bro:see:`HTTP::log_http` event and we are interested in the MIME type, size of the file ("response_body_len") and the originator host ("orig_h"). We use the MIME type as our key and create observers for the other two values. .. code:: bro From c5ab33d88f230a48d1b76d140a83ce9a9c07dc81 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 21 Jan 2014 11:43:35 -0600 Subject: [PATCH 033/254] Reformat line width of some docs (i.e. `fmt -72`). --- doc/broids/index.rst | 60 +++++++++++++------ doc/httpmonitor/index.rst | 120 +++++++++++++++++++++++--------------- doc/mimestats/index.rst | 49 +++++++++++----- 3 files changed, 149 insertions(+), 80 deletions(-) diff --git a/doc/broids/index.rst b/doc/broids/index.rst index 1d5f63ec7f..b3317815a7 100644 --- a/doc/broids/index.rst +++ b/doc/broids/index.rst @@ -5,17 +5,24 @@ Bro IDS ======= -An Intrusion Detection System (IDS) allows you to detect suspicious activities happening on your network as a result of a past or active -attack. Because of its programming capabilities, Bro can easily be configured to behave like traditional IDSs and detect common attacks -with well known patterns, or you can create your own scripts to detect conditions specific to your particular case. +An Intrusion Detection System (IDS) allows you to detect suspicious +activities happening on your network as a result of a past or active +attack. Because of its programming capabilities, Bro can easily be +configured to behave like traditional IDSs and detect common attacks +with well known patterns, or you can create your own scripts to detect +conditions specific to your particular case. -In the following sections, we present a few examples of common uses of Bro as an IDS. +In the following sections, we present a few examples of common uses of +Bro as an IDS. ------------------------------------------------ Detecting an FTP Bruteforce attack and notifying ------------------------------------------------ -For the purpose of this exercise, we define FTP bruteforcing as too many rejected usernames and passwords occurring from a single address. -We start by defining a threshold for the number of attempts and a monitoring interval in minutes. + +For the purpose of this exercise, we define FTP bruteforcing as too many +rejected usernames and passwords occurring from a single address. We +start by defining a threshold for the number of attempts and a +monitoring interval in minutes. .. code:: bro @@ -29,8 +36,13 @@ We start by defining a threshold for the number of attempts and a monitoring int const bruteforce_measurement_interval = 15mins &redef; } -Now, using the ftp_reply event, we check for error codes from the `500 series `_ for the "USER" and "PASS" commands, representing rejected usernames or passwords. For this, we can use the :bro:see:`FTP::parse_ftp_reply_code` function to break down the reply code and check if the first digit is a "5" or not. If true, we then use the -:ref:`Summary Statistics Framework ` to keep track of the number of failed attempts. +Now, using the ftp_reply event, we check for error codes from the `500 +series `_ +for the "USER" and "PASS" commands, representing rejected usernames or +passwords. For this, we can use the :bro:see:`FTP::parse_ftp_reply_code` +function to break down the reply code and check if the first digit is a +"5" or not. If true, we then use the :ref:`Summary Statistics Framework +` to keep track of the number of failed attempts. .. code:: bro @@ -44,7 +56,8 @@ Now, using the ftp_reply event, we check for error codes from the `500 series `. For this, we need to define a new Notice type and trigger the alarm under the right -conditions. Below is the final code for our script. +Printing a message on the console is a good start but it will be better +if we raise an alarm instead using the :ref:`Notice Framework +`. For this, we need to define a new Notice type and +trigger the alarm under the right conditions. Below is the final code +for our script. .. code:: bro @@ -135,17 +151,27 @@ conditions. Below is the final code for our script. } } -As a final note, the :doc:`detect-bruteforcing.bro ` script above is include with Bro out of the box, so you only need to load it at startup to instruct Bro to detect and notify of FTP bruteforce attacks. +As a final note, the :doc:`detect-bruteforcing.bro +` script above is +include with Bro out of the box, so you only need to load it at startup +to instruct Bro to detect and notify of FTP bruteforce attacks. ------------- Other Attacks ------------- + Detecting SQL Injection attacks ------------------------------- + Checking files against known malware hashes ------------------------------------------- -Files transmitted on your network could either be completely harmless or contain viruses and other threats. One possible action against -this threat is to compute the hashes of the files and compare them against a list of known malware hashes. Bro simplifies this task -by offering a :doc:`detect-MHR.bro ` script that creates and compares -hashes against the `Malware Hash Registry `_ maintained by Team Cymru. You only need to load this -script along with your other scripts at startup time. + +Files transmitted on your network could either be completely harmless or +contain viruses and other threats. One possible action against this +threat is to compute the hashes of the files and compare them against a +list of known malware hashes. Bro simplifies this task by offering a +:doc:`detect-MHR.bro ` +script that creates and compares hashes against the `Malware Hash +Registry `_ maintained by Team +Cymru. You only need to load this script along with your other scripts +at startup time. diff --git a/doc/httpmonitor/index.rst b/doc/httpmonitor/index.rst index 9b640c63ec..6122421e37 100644 --- a/doc/httpmonitor/index.rst +++ b/doc/httpmonitor/index.rst @@ -5,71 +5,85 @@ Monitoring HTTP Traffic with Bro ================================ -Bro can be used to log the entire HTTP traffic from your network to the http.log file. -This file can then be used for analysis and auditing purposes. +Bro can be used to log the entire HTTP traffic from your network to the +http.log file. This file can then be used for analysis and auditing +purposes. -In the sections below we briefly explain the structure of the http.log file. Then, we -show you how to perform basic HTTP traffic monitoring and analysis tasks with Bro. Some -of these ideas and techniques can later be applied to monitor different protocols in a -similar way. +In the sections below we briefly explain the structure of the http.log +file. Then, we show you how to perform basic HTTP traffic monitoring and +analysis tasks with Bro. Some of these ideas and techniques can later be +applied to monitor different protocols in a similar way. ---------------------------- Introduction to the HTTP log ---------------------------- -The http.log file contains a summary of all HTTP requests and responses sent over a Bro-monitored -network. Here are the first few columns of +The http.log file contains a summary of all HTTP requests and responses +sent over a Bro-monitored network. Here are the first few columns of ``http.log``:: # ts uid orig_h orig_p resp_h resp_p 1311627961.8 HSH4uV8KVJg 192.168.1.100 52303 192.150.187.43 80 -Every single line in this log starts with a timestamp, a unique connection identifier (UID), and a -connection 4-tuple (originator host/port and responder host/port). The UID can be used to -identify all logged activity (possibly across multiple log files) associated -with a given connection 4-tuple over its lifetime. +Every single line in this log starts with a timestamp, a unique +connection identifier (UID), and a connection 4-tuple (originator +host/port and responder host/port). The UID can be used to identify all +logged activity (possibly across multiple log files) associated with a +given connection 4-tuple over its lifetime. -The remaining columns detail the activity that's occurring. For example, the columns on the line below -(shortened for brevity) show a request to the root of Bro website:: +The remaining columns detail the activity that's occurring. For +example, the columns on the line below (shortened for brevity) show a +request to the root of Bro website:: # method host uri referrer user_agent GET bro.org / - <...>Chrome/12.0.742.122<...> -Network administrators and security engineers, for instance, can use the information in this log to understand -the HTTP activity on the network and troubleshoot network problems or search for anomalous activities. At this -point, we would like to stress out the fact that there is no just one right way to perform analysis; it will -depend on the expertise of the person doing the analysis and the specific details of the task to accomplish. +Network administrators and security engineers, for instance, can use the +information in this log to understand the HTTP activity on the network +and troubleshoot network problems or search for anomalous activities. At +this point, we would like to stress out the fact that there is no just +one right way to perform analysis; it will depend on the expertise of +the person doing the analysis and the specific details of the task to +accomplish. -For more information about how to handle the HTTP protocol in Bro, including a complete list -of the fields available in http.log, go to Bro's -:doc:`HTTP script reference `. +For more information about how to handle the HTTP protocol in Bro, +including a complete list of the fields available in http.log, go to +Bro's :doc:`HTTP script reference +`. ------------------------ Detecting a Proxy Server ------------------------ -A proxy server is a device on your network configured to request a service on behalf of a third system; one of the -most common examples is a Web proxy server. A client without Internet access connects to the proxy and requests -a Web page; the proxy then sends the request to the actual Web server, receives the response and passes it to the original +A proxy server is a device on your network configured to request a +service on behalf of a third system; one of the most common examples is +a Web proxy server. A client without Internet access connects to the +proxy and requests a Web page; the proxy then sends the request to the +actual Web server, receives the response and passes it to the original client. -Proxies were conceived to help manage a network and provide better encapsulation. By themselves, proxies are not a security -threat, but a misconfigured or unauthorized proxy can allow others, either inside or outside the network, to access any -Web site and even conduct malicious activities anonymously using the network resources. +Proxies were conceived to help manage a network and provide better +encapsulation. By themselves, proxies are not a security threat, but a +misconfigured or unauthorized proxy can allow others, either inside or +outside the network, to access any Web site and even conduct malicious +activities anonymously using the network resources. What Proxy Server traffic looks like ------------------------------------- -In general, when a client starts talking with a proxy server, the traffic consists of two parts: (i) a GET request, and -(ii) an HTTP/ reply:: +In general, when a client starts talking with a proxy server, the +traffic consists of two parts: (i) a GET request, and (ii) an HTTP/ +reply:: Request: GET http://www.bro.org/ HTTP/1.1 Reply: HTTP/1.0 200 OK -This will differ from traffic between a client and a normal Web server because GET requests should not include "http" on -the string. So we can use this to identify a proxy server. +This will differ from traffic between a client and a normal Web server +because GET requests should not include "http" on the string. So we can +use this to identify a proxy server. -We can write a basic script in Bro to handle the http_reply event and detect a reply for a ``GET http://`` request. +We can write a basic script in Bro to handle the http_reply event and +detect a reply for a ``GET http://`` request. .. code:: bro @@ -81,8 +95,10 @@ We can write a basic script in Bro to handle the http_reply event and detect a r } } -Basically, the script is checking for a "200 OK" status code on a reply for a request that includes "http:". In reality, the HTTP -protocol defines several success status codes other than 200, so we will extend our basic script to also consider the additional codes. +Basically, the script is checking for a "200 OK" status code on a reply +for a request that includes "http:". In reality, the HTTP protocol +defines several success status codes other than 200, so we will extend +our basic script to also consider the additional codes. .. code:: bro @@ -112,7 +128,8 @@ protocol defines several success status codes other than 200, so we will extend } } -Next, we will make sure that the responding proxy is part of our local network. +Next, we will make sure that the responding proxy is part of our local +network. .. code:: bro @@ -142,9 +159,12 @@ Next, we will make sure that the responding proxy is part of our local network. } } -Finally, our goal should be to generate an alert when a proxy has been detected instead of printing a message on the console output. -For that, we will tag the traffic accordingly and define a new ``Open_Proxy`` ``Notice`` type to alert of all tagged communications. Once a -notification has been fired, we will further suppress it for one day. Below is the complete script. +Finally, our goal should be to generate an alert when a proxy has been +detected instead of printing a message on the console output. For that, +we will tag the traffic accordingly and define a new ``Open_Proxy`` +``Notice`` type to alert of all tagged communications. Once a +notification has been fired, we will further suppress it for one day. +Below is the complete script. .. code:: bro @@ -216,11 +236,14 @@ notification has been fired, we will further suppress it for one day. Below is t Inspecting Files ---------------- -Files are often transmitted on regular HTTP conversations between a client and a server. Most of the time these files are harmless, -just images and some other multimedia content, but there are also types of files, specially executable files, that can damage -your system. We can instruct Bro to create a copy of all executable files that it sees for later analysis using the -:ref:`File Analysis Framework ` -(introduced with Bro 2.2) as shown in the following script. +Files are often transmitted on regular HTTP conversations between a +client and a server. Most of the time these files are harmless, just +images and some other multimedia content, but there are also types of +files, specially executable files, that can damage your system. We can +instruct Bro to create a copy of all executable files that it sees for +later analysis using the :ref:`File Analysis Framework +` (introduced with Bro 2.2) as shown in the +following script. .. code:: bro @@ -239,9 +262,11 @@ your system. We can instruct Bro to create a copy of all executable files that i Files::add_analyzer(f, Files::ANALYZER_EXTRACT, [$extract_filename=fname]); } -Bro will extract all files from the traffic and write them on a new ``extract_files/`` subdirectory and change the file name with the right -suffix (extension) based on the content of the ext_map table. So, if you want to do the same for other extracted files besides executables -you just need to add those types to the ``ext_map`` table like this. +Bro will extract all files from the traffic and write them on a new +``extract_files/`` subdirectory and change the file name with the right +suffix (extension) based on the content of the ext_map table. So, if you +want to do the same for other extracted files besides executables you +just need to add those types to the ``ext_map`` table like this. .. code:: bro @@ -253,4 +278,5 @@ you just need to add those types to the ``ext_map`` table like this. ["text/html"] = "html", } &default =""; -Bro will now write the appropriate suffix for text, JPEG, PNG, and HTML files stored in the ``extract_files/`` subdirectory. +Bro will now write the appropriate suffix for text, JPEG, PNG, and HTML +files stored in the ``extract_files/`` subdirectory. diff --git a/doc/mimestats/index.rst b/doc/mimestats/index.rst index 88499a5d6e..f81431eb8b 100644 --- a/doc/mimestats/index.rst +++ b/doc/mimestats/index.rst @@ -5,24 +5,37 @@ MIME Type Statistics ==================== -Files are constantly transmitted over HTTP on regular networks. These files belong to a specific category (i.e., executable, text, image, etc.) identified -by a `Multipurpose Internet Mail Extension (MIME) `_. Although MIME was originally developed to identify the type of -non-text attachments on email, it is also used by Web browser to identify the type of files transmitted and present them accordingly. +Files are constantly transmitted over HTTP on regular networks. These +files belong to a specific category (i.e., executable, text, image, +etc.) identified by a `Multipurpose Internet Mail Extension (MIME) +`_. Although MIME was originally +developed to identify the type of non-text attachments on email, it is +also used by Web browser to identify the type of files transmitted and +present them accordingly. -In this tutorial, we will show how to use the Sumstats Framework to collect some statistics information based on MIME types, specifically the total number of -occurrences, size in bytes, and number of unique hosts transmitting files over HTTP per each type. For instructions about extracting and creating a local copy -of these files, visit :ref:`this ` tutorial instead. +In this tutorial, we will show how to use the Sumstats Framework to +collect some statistics information based on MIME types, specifically +the total number of occurrences, size in bytes, and number of unique +hosts transmitting files over HTTP per each type. For instructions about +extracting and creating a local copy of these files, visit :ref:`this +` tutorial instead. ------------------------------------------------ MIME Statistics with Sumstats ------------------------------------------------ -When working with the :ref:`Summary Statistics Framework `, you need to define three different pieces: (i) Observations, where -the event is observed and fed into the framework. (ii) Reducers, where observations are collected and measured. (iii) Sumstats, where the main functionality -is implemented. -So, we start by defining our observation along with a record to store all statistics values and an observation interval. We are conducting our observation on -the :bro:see:`HTTP::log_http` event and we are interested in the MIME type, size of the file ("response_body_len") and the originator host ("orig_h"). We use the MIME -type as our key and create observers for the other two values. +When working with the :ref:`Summary Statistics Framework +`, you need to define three different pieces: (i) +Observations, where the event is observed and fed into the framework. +(ii) Reducers, where observations are collected and measured. (iii) +Sumstats, where the main functionality is implemented. + +So, we start by defining our observation along with a record to store +all statistics values and an observation interval. We are conducting our +observation on the :bro:see:`HTTP::log_http` event and we are interested +in the MIME type, size of the file ("response_body_len") and the +originator host ("orig_h"). We use the MIME type as our key and create +observers for the other two values. .. code:: bro @@ -56,15 +69,18 @@ type as our key and create observers for the other two values. } } -Next, we create the reducers. The first one will accumulate file sizes and the second one will make sure we only store a host ID once. Below is the partial code. +Next, we create the reducers. The first one will accumulate file sizes +and the second one will make sure we only store a host ID once. Below is +the partial code. .. code:: bro local r1: SumStats::Reducer = [$stream="mime.bytes", $apply=set(SumStats::SUM)]; local r2: SumStats::Reducer = [$stream="mime.hits", $apply=set(SumStats::UNIQUE)]; -In our final step, we create the SumStats where we check for the observation interval and once it expires, we populate the record (defined above) with all the -relevant data and write it to a log. +In our final step, we create the SumStats where we check for the +observation interval and once it expires, we populate the record +(defined above) with all the relevant data and write it to a log. .. code:: bro @@ -83,7 +99,8 @@ relevant data and write it to a log. Log::write(LOG, l); }]); -Putting everything together we end up with the following final code for our script. +Putting everything together we end up with the following final code for +our script. .. code:: bro From e18084b68dfcec3f2d3f742364bfa06cbe06812c Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 21 Jan 2014 16:01:55 -0600 Subject: [PATCH 034/254] Add unit tests for new Bro Manual docs. --- doc/broids/index.rst | 127 ++---------- doc/httpmonitor/file_extraction.bro | 24 +++ doc/httpmonitor/http_proxy_01.bro | 5 + doc/httpmonitor/http_proxy_02.bro | 26 +++ doc/httpmonitor/http_proxy_03.bro | 31 +++ doc/httpmonitor/http_proxy_04.bro | 40 ++++ doc/httpmonitor/index.rst | 195 ++++-------------- doc/mimestats/index.rst | 120 ++--------- doc/mimestats/mimestats.bro | 64 ++++++ .../btest-doc.sphinx.file_extraction#1 | 14 ++ .../btest-doc.sphinx.ftp-bruteforce#1 | 24 +++ .../btest-doc.sphinx.http_proxy_01#1 | 9 + .../btest-doc.sphinx.http_proxy_02#1 | 9 + .../btest-doc.sphinx.http_proxy_03#1 | 9 + .../btest-doc.sphinx.http_proxy_04#1 | 24 +++ .../output | 28 +++ .../output | 9 + .../output | 30 +++ .../output | 35 ++++ .../output | 44 ++++ .../output | 39 ++++ .../output | 8 + .../output | 18 ++ .../output | 68 ++++++ .../output | 21 ++ .../output | 13 ++ .../output | 27 +++ .../output | 64 ++++++ .../btest-doc.sphinx.mimestats#1 | 31 +++ testing/btest/Traces/ftp/bruteforce.pcap | Bin 0 -> 55167 bytes testing/btest/Traces/http/bro.org.pcap | Bin 0 -> 506533 bytes testing/btest/Traces/http/proxy.pcap | Bin 0 -> 18521 bytes .../btest/doc/sphinx/file_extraction.btest | 1 + testing/btest/doc/sphinx/ftp-bruteforce.btest | 2 + testing/btest/doc/sphinx/http_proxy_01.btest | 1 + testing/btest/doc/sphinx/http_proxy_02.btest | 1 + testing/btest/doc/sphinx/http_proxy_03.btest | 1 + testing/btest/doc/sphinx/http_proxy_04.btest | 2 + ...-doc_httpmonitor_file_extraction_bro.btest | 28 +++ ...de-doc_httpmonitor_http_proxy_01_bro.btest | 9 + ...de-doc_httpmonitor_http_proxy_02_bro.btest | 30 +++ ...de-doc_httpmonitor_http_proxy_03_bro.btest | 35 ++++ ...de-doc_httpmonitor_http_proxy_04_bro.btest | 44 ++++ .../include-doc_mimestats_mimestats_bro.btest | 39 ++++ ...nclude-doc_mimestats_mimestats_bro@2.btest | 8 + ...nclude-doc_mimestats_mimestats_bro@3.btest | 18 ++ ...nclude-doc_mimestats_mimestats_bro@4.btest | 68 ++++++ ...rotocols_ftp_detect-bruteforcing_bro.btest | 21 ++ ...tocols_ftp_detect-bruteforcing_bro@2.btest | 13 ++ ...tocols_ftp_detect-bruteforcing_bro@3.btest | 27 +++ ...tocols_ftp_detect-bruteforcing_bro@4.btest | 64 ++++++ testing/btest/doc/sphinx/mimestats.btest | 2 + 52 files changed, 1196 insertions(+), 374 deletions(-) create mode 100644 doc/httpmonitor/file_extraction.bro create mode 100644 doc/httpmonitor/http_proxy_01.bro create mode 100644 doc/httpmonitor/http_proxy_02.bro create mode 100644 doc/httpmonitor/http_proxy_03.bro create mode 100644 doc/httpmonitor/http_proxy_04.bro create mode 100644 doc/mimestats/mimestats.bro create mode 100644 testing/btest/Baseline/doc.sphinx.file_extraction/btest-doc.sphinx.file_extraction#1 create mode 100644 testing/btest/Baseline/doc.sphinx.ftp-bruteforce/btest-doc.sphinx.ftp-bruteforce#1 create mode 100644 testing/btest/Baseline/doc.sphinx.http_proxy_01/btest-doc.sphinx.http_proxy_01#1 create mode 100644 testing/btest/Baseline/doc.sphinx.http_proxy_02/btest-doc.sphinx.http_proxy_02#1 create mode 100644 testing/btest/Baseline/doc.sphinx.http_proxy_03/btest-doc.sphinx.http_proxy_03#1 create mode 100644 testing/btest/Baseline/doc.sphinx.http_proxy_04/btest-doc.sphinx.http_proxy_04#1 create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_file_extraction_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_01_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_02_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_03_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_04_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@2/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@3/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@4/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@2/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@3/output create mode 100644 testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@4/output create mode 100644 testing/btest/Baseline/doc.sphinx.mimestats/btest-doc.sphinx.mimestats#1 create mode 100644 testing/btest/Traces/ftp/bruteforce.pcap create mode 100644 testing/btest/Traces/http/bro.org.pcap create mode 100644 testing/btest/Traces/http/proxy.pcap create mode 100644 testing/btest/doc/sphinx/file_extraction.btest create mode 100644 testing/btest/doc/sphinx/ftp-bruteforce.btest create mode 100644 testing/btest/doc/sphinx/http_proxy_01.btest create mode 100644 testing/btest/doc/sphinx/http_proxy_02.btest create mode 100644 testing/btest/doc/sphinx/http_proxy_03.btest create mode 100644 testing/btest/doc/sphinx/http_proxy_04.btest create mode 100644 testing/btest/doc/sphinx/include-doc_httpmonitor_file_extraction_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_01_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_02_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_03_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_04_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro.btest create mode 100644 testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@2.btest create mode 100644 testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@3.btest create mode 100644 testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@4.btest create mode 100644 testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro.btest create mode 100644 testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@2.btest create mode 100644 testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@3.btest create mode 100644 testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@4.btest create mode 100644 testing/btest/doc/sphinx/mimestats.btest diff --git a/doc/broids/index.rst b/doc/broids/index.rst index b3317815a7..46e0d6ded6 100644 --- a/doc/broids/index.rst +++ b/doc/broids/index.rst @@ -22,19 +22,10 @@ Detecting an FTP Bruteforce attack and notifying For the purpose of this exercise, we define FTP bruteforcing as too many rejected usernames and passwords occurring from a single address. We start by defining a threshold for the number of attempts and a -monitoring interval in minutes. +monitoring interval in minutes as well as a new notice type. - .. code:: bro - - export { - ## How many rejected usernames or passwords are required before being - ## considered to be bruteforcing. - const bruteforce_threshold: double = 20 &redef; - - ## The time period in which the threshold needs to be crossed before - ## being reset. - const bruteforce_measurement_interval = 15mins &redef; - } +.. btest-include:: ${BRO_SRC_ROOT}/scripts/policy/protocols/ftp/detect-bruteforcing.bro + :lines: 9-25 Now, using the ftp_reply event, we check for error codes from the `500 series `_ @@ -44,112 +35,24 @@ function to break down the reply code and check if the first digit is a "5" or not. If true, we then use the :ref:`Summary Statistics Framework ` to keep track of the number of failed attempts. - .. code:: bro +.. btest-include:: ${BRO_SRC_ROOT}/scripts/policy/protocols/ftp/detect-bruteforcing.bro + :lines: 52-60 - event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) - { - local cmd = c$ftp$cmdarg$cmd; - if ( cmd == "USER" || cmd == "PASS" ) - { - if ( FTP::parse_ftp_reply_code(code)$x == 5 ) - SumStats::observe("ftp.failed_auth", [$host=c$id$orig_h], [$str=cat(c$id$resp_h)]); - } - } +Next, we use the SumStats framework to raise a notice of the attack of +the attack when the number of failed attempts exceeds the specified +threshold during the measuring interval. -Next, we use the SumStats framework to automatically print a message on -the console alerting of the attack when the number of failed attempts -exceeds the specified threshold during the measuring interval. +.. btest-include:: ${BRO_SRC_ROOT}/scripts/policy/protocols/ftp/detect-bruteforcing.bro + :lines: 28-50 - .. code:: bro +Below is the final code for our script. - event bro_init() - { - local r1: SumStats::Reducer = [$stream="ftp.failed_auth", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(bruteforce_threshold+2)]; - SumStats::create([$name="ftp-detect-bruteforcing", - $epoch=bruteforce_measurement_interval, - $reducers=set(r1), - $threshold_val(key: SumStats::Key, result: SumStats::Result) = - { - return result["ftp.failed_auth"]$num+0.0; - }, - $threshold=bruteforce_threshold, - $threshold_crossed(key: SumStats::Key, result: SumStats::Result) = - { - local r = result["ftp.failed_auth"]; - local dur = duration_to_mins_secs(r$end-r$begin); - local plural = r$unique>1 ? "s" : ""; - local message = fmt("%s had %d failed logins on %d FTP server%s in %s", key$host, r$num, r$unique, plural, dur); - }]); - } +.. btest-include:: ${BRO_SRC_ROOT}/scripts/policy/protocols/ftp/detect-bruteforcing.bro -Printing a message on the console is a good start but it will be better -if we raise an alarm instead using the :ref:`Notice Framework -`. For this, we need to define a new Notice type and -trigger the alarm under the right conditions. Below is the final code -for our script. +.. btest:: ftp-bruteforce - .. code:: bro - - ##! FTP brute-forcing detector, triggering when too many rejected usernames or - ##! failed passwords have occurred from a single address. - - @load base/protocols/ftp - @load base/frameworks/sumstats - - @load base/utils/time - - module FTP; - - export { - redef enum Notice::Type += { - ## Indicates a host bruteforcing FTP logins by watching for too - ## many rejected usernames or failed passwords. - Bruteforcing - }; - - ## How many rejected usernames or passwords are required before being - ## considered to be bruteforcing. - const bruteforce_threshold: double = 20 &redef; - - ## The time period in which the threshold needs to be crossed before - ## being reset. - const bruteforce_measurement_interval = 15mins &redef; - } - - - event bro_init() - { - local r1: SumStats::Reducer = [$stream="ftp.failed_auth", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(bruteforce_threshold+2)]; - SumStats::create([$name="ftp-detect-bruteforcing", - $epoch=bruteforce_measurement_interval, - $reducers=set(r1), - $threshold_val(key: SumStats::Key, result: SumStats::Result) = - { - return result["ftp.failed_auth"]$num+0.0; - }, - $threshold=bruteforce_threshold, - $threshold_crossed(key: SumStats::Key, result: SumStats::Result) = - { - local r = result["ftp.failed_auth"]; - local dur = duration_to_mins_secs(r$end-r$begin); - local plural = r$unique>1 ? "s" : ""; - local message = fmt("%s had %d failed logins on %d FTP server%s in %s", key$host, r$num, r$unique, plural, dur); - NOTICE([$note=FTP::Bruteforcing, - $src=key$host, - $msg=message, - $identifier=cat(key$host)]); - }]); - } - - event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) - { - local cmd = c$ftp$cmdarg$cmd; - if ( cmd == "USER" || cmd == "PASS" ) - { - if ( FTP::parse_ftp_reply_code(code)$x == 5 ) - SumStats::observe("ftp.failed_auth", [$host=c$id$orig_h], [$str=cat(c$id$resp_h)]); - } - } + @TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/ftp/bruteforce.pcap protocols/ftp/detect-bruteforcing.bro + @TEST-EXEC: btest-rst-include notice.log As a final note, the :doc:`detect-bruteforcing.bro ` script above is diff --git a/doc/httpmonitor/file_extraction.bro b/doc/httpmonitor/file_extraction.bro new file mode 100644 index 0000000000..b2318c595e --- /dev/null +++ b/doc/httpmonitor/file_extraction.bro @@ -0,0 +1,24 @@ + +global mime_to_ext: table[string] of string = { + ["application/x-dosexec"] = "exe", + ["text/plain"] = "txt", + ["image/jpeg"] = "jpg", + ["image/png"] = "png", + ["text/html"] = "html", +}; + +event file_new(f: fa_file) + { + if ( f$source != "HTTP" ) + return; + + if ( ! f?$mime_type ) + return; + + if ( f$mime_type !in mime_to_ext ) + return; + + local fname = fmt("%s-%s.%s", f$source, f$id, mime_to_ext[f$mime_type]); + print fmt("Extracting file %s", fname); + Files::add_analyzer(f, Files::ANALYZER_EXTRACT, [$extract_filename=fname]); + } diff --git a/doc/httpmonitor/http_proxy_01.bro b/doc/httpmonitor/http_proxy_01.bro new file mode 100644 index 0000000000..76555b6646 --- /dev/null +++ b/doc/httpmonitor/http_proxy_01.bro @@ -0,0 +1,5 @@ +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code == 200 ) + print fmt("A local server is acting as an open proxy: %s", c$id$resp_h); + } diff --git a/doc/httpmonitor/http_proxy_02.bro b/doc/httpmonitor/http_proxy_02.bro new file mode 100644 index 0000000000..cdbd722619 --- /dev/null +++ b/doc/httpmonitor/http_proxy_02.bro @@ -0,0 +1,26 @@ + +module HTTP; + +export { + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; +} + +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( /^[hH][tT][tT][pP]:/ in c$http$uri && + c$http$status_code in HTTP::success_status_codes ) + print fmt("A local server is acting as an open proxy: %s", c$id$resp_h); + } diff --git a/doc/httpmonitor/http_proxy_03.bro b/doc/httpmonitor/http_proxy_03.bro new file mode 100644 index 0000000000..17bfdcb95b --- /dev/null +++ b/doc/httpmonitor/http_proxy_03.bro @@ -0,0 +1,31 @@ + +@load base/utils/site + +redef Site::local_nets += { 192.168.0.0/16 }; + +module HTTP; + +export { + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; +} + +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( Site::is_local_addr(c$id$resp_h) && + /^[hH][tT][tT][pP]:/ in c$http$uri && + c$http$status_code in HTTP::success_status_codes ) + print fmt("A local server is acting as an open proxy: %s", c$id$resp_h); + } diff --git a/doc/httpmonitor/http_proxy_04.bro b/doc/httpmonitor/http_proxy_04.bro new file mode 100644 index 0000000000..1f11be3670 --- /dev/null +++ b/doc/httpmonitor/http_proxy_04.bro @@ -0,0 +1,40 @@ +@load base/utils/site +@load base/frameworks/notice + +redef Site::local_nets += { 192.168.0.0/16 }; + +module HTTP; + +export { + + redef enum Notice::Type += { + Open_Proxy + }; + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; +} + +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( Site::is_local_addr(c$id$resp_h) && + /^[hH][tT][tT][pP]:/ in c$http$uri && + c$http$status_code in HTTP::success_status_codes ) + NOTICE([$note=HTTP::Open_Proxy, + $msg=fmt("A local server is acting as an open proxy: %s", + c$id$resp_h), + $conn=c, + $identifier=cat(c$id$resp_h), + $suppress_for=1day]); + } diff --git a/doc/httpmonitor/index.rst b/doc/httpmonitor/index.rst index 6122421e37..f6b2f5e122 100644 --- a/doc/httpmonitor/index.rst +++ b/doc/httpmonitor/index.rst @@ -85,79 +85,37 @@ use this to identify a proxy server. We can write a basic script in Bro to handle the http_reply event and detect a reply for a ``GET http://`` request. - .. code:: bro +.. btest-include:: ${DOC_ROOT}/httpmonitor/http_proxy_01.bro - event http_reply(c: connection, version: string, code: count, reason: string) - { - if ( /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code == 200 ) - { - print fmt("A local server is acting as an open proxy: ", c$id$resp_h); - } - } +.. btest:: http_proxy_01 + + @TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/http/proxy.pcap ${DOC_ROOT}/httpmonitor/http_proxy_01.bro Basically, the script is checking for a "200 OK" status code on a reply -for a request that includes "http:". In reality, the HTTP protocol -defines several success status codes other than 200, so we will extend -our basic script to also consider the additional codes. +for a request that includes "http:" (case insensitive). In reality, the +HTTP protocol defines several success status codes other than 200, so we +will extend our basic script to also consider the additional codes. - .. code:: bro +.. btest-include:: ${DOC_ROOT}/httpmonitor/http_proxy_02.bro - export { +.. btest:: http_proxy_02 - global success_status_codes: set[count] = { - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 226, - 304 - }; - - } - - event http_reply(c: connection, version: string, code: count, reason: string) - { - if ( /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code in success_status_codes ) - { - print fmt("A local server is acting as an open proxy: ", c$id$resp_h); - } - } + @TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/http/proxy.pcap ${DOC_ROOT}/httpmonitor/http_proxy_02.bro Next, we will make sure that the responding proxy is part of our local network. - .. code:: bro +.. btest-include:: ${DOC_ROOT}/httpmonitor/http_proxy_03.bro - export { +.. btest:: http_proxy_03 - global success_status_codes: set[count] = { - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 226, - 304 - }; + @TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/http/proxy.pcap ${DOC_ROOT}/httpmonitor/http_proxy_03.bro - } +.. note:: - event http_reply(c: connection, version: string, code: count, reason: string) - { - if ( Site::is_local_addr(c$id$resp_h) && /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code in success_status_codes ) - { - print fmt("A local server is acting as an open proxy: ", c$id$resp_h); - } - } + The redefinition of :bro:see:`Site::local_nets` is only done inside + this script to make it a self-contained example. It's typically + redefined somewhere else. Finally, our goal should be to generate an alert when a proxy has been detected instead of printing a message on the console output. For that, @@ -166,71 +124,18 @@ we will tag the traffic accordingly and define a new ``Open_Proxy`` notification has been fired, we will further suppress it for one day. Below is the complete script. - .. code:: bro +.. btest-include:: ${DOC_ROOT}/httpmonitor/http_proxy_04.bro - @load base/frameworks/notice +.. btest:: http_proxy_04 - module HTTP; + @TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/http/proxy.pcap ${DOC_ROOT}/httpmonitor/http_proxy_04.bro + @TEST-EXEC: btest-rst-include notice.log - export { - - redef enum HTTP::Tags += { - OPEN_PROXY_TAG - }; - redef enum Notice::Type += { - Open_Proxy - }; - - global success_status_codes: set[count] = { - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 226, - 304 - }; - - } - - redef Notice::emailed_types += { - Open_Proxy, - }; - - function open_proxy_only(rec: HTTP::Info) : bool - { - # Only write out connections with the OPEN_PROXY_TAG. - return OPEN_PROXY_TAG in rec$tags; - } - - event http_reply(c: connection, version: string, code: count, reason: string) - { - # make sure responding host is local - #if ( Site::is_local_addr(c$id$resp_h) && /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code in success_status_codes ) - { - add c$http$tags[OPEN_PROXY_TAG]; - local ident = cat(c$id$resp_h); - if ( c$http?$host ) #check if the optional host field exists in http - { - print fmt("Originator host: %s", c$id$orig_h); - NOTICE([$note=HTTP::Open_Proxy, - $msg=cat("A local server is acting as an open proxy: ", c$id$resp_h), - $conn=c, $identifier=cat(ident, c$id$resp_h), - $suppress_for=1day]); - } - } - } - - event bro_init() - { - #Creating a new filter for all open proxy logs. - local filter: Log::Filter = [$name="open_proxy", $path="open_proxy", $pred=open_proxy_only]; - Log::add_filter(HTTP::LOG, filter); - } +Note that this script only logs the presence of the proxy to +``notice.log``, but if an additional email is desired (and email +functionality is enabled), then that's done simply by redefining +:bro:see:`Notice::emailed_types` to add the ``Open_proxy`` notice type +to it. ---------------- Inspecting Files @@ -240,43 +145,19 @@ Files are often transmitted on regular HTTP conversations between a client and a server. Most of the time these files are harmless, just images and some other multimedia content, but there are also types of files, specially executable files, that can damage your system. We can -instruct Bro to create a copy of all executable files that it sees for -later analysis using the :ref:`File Analysis Framework -` (introduced with Bro 2.2) as shown in the -following script. +instruct Bro to create a copy of all files of certain types that it sees +using the :ref:`File Analysis Framework ` +(introduced with Bro 2.2): - .. code:: bro +.. btest-include:: ${DOC_ROOT}/httpmonitor/file_extraction.bro - global ext_map: table[string] of string = { - ["application/x-dosexec"] = "exe", - } &default =""; +.. btest:: file_extraction - event file_new(f: fa_file) - { - local ext = ""; + @TEST-EXEC: btest-rst-cmd -n 5 bro -r ${TRACES}/http/bro.org.pcap ${DOC_ROOT}/httpmonitor/file_extraction.bro - if ( f?$mime_type ) - ext = ext_map[f$mime_type]; - - local fname = fmt("%s-%s.%s", f$source, f$id, ext); - Files::add_analyzer(f, Files::ANALYZER_EXTRACT, [$extract_filename=fname]); - } - -Bro will extract all files from the traffic and write them on a new -``extract_files/`` subdirectory and change the file name with the right -suffix (extension) based on the content of the ext_map table. So, if you -want to do the same for other extracted files besides executables you -just need to add those types to the ``ext_map`` table like this. - - .. code:: bro - - global ext_map: table[string] of string = { - ["application/x-dosexec"] = "exe", - ["text/plain"] = "txt", - ["image/jpeg"] = "jpg", - ["image/png"] = "png", - ["text/html"] = "html", - } &default =""; - -Bro will now write the appropriate suffix for text, JPEG, PNG, and HTML -files stored in the ``extract_files/`` subdirectory. +Here, the ``mime_to_ext`` table serves two purposes. It defines which +mime types to extract and also the file suffix of the extracted files. +Extracted files are written to a new ``extract_files`` subdirectory. +Also note that the first conditional in the :bro:see:`file_new` event +handler can be removed to make this behavior generic to other protocols +besides HTTP. diff --git a/doc/mimestats/index.rst b/doc/mimestats/index.rst index f81431eb8b..df17f4872f 100644 --- a/doc/mimestats/index.rst +++ b/doc/mimestats/index.rst @@ -37,125 +37,35 @@ in the MIME type, size of the file ("response_body_len") and the originator host ("orig_h"). We use the MIME type as our key and create observers for the other two values. - .. code:: bro - - export { - redef enum Log::ID += { LOG }; - type Info: record { - ## Timestamp when the log line was finished and written. - ts: time &log; - ## Time interval that the log line covers. - ts_delta: interval &log; - ## The mime type - mtype: string &log; - ## The number of unique local hosts that fetched this mime type - uniq_hosts: count &log; - ## The number of hits to the mime type - hits: count &log; - ## The total number of bytes received by this mime type - bytes: count &log; - }; - - ## The frequency of logging the stats collected by this script. - const break_interval = 5mins &redef; - } - - event HTTP::log_http(rec: HTTP::Info) - { - if(Site::is_local_addr(rec$id$orig_h) && rec?$resp_mime_types) { - local mime_type = rec$resp_mime_types[0]; - SumStats::observe("mime.bytes", [$str=mime_type], [$num=rec$response_body_len]); - SumStats::observe("mime.hits", [$str=mime_type], [$str=cat(rec$id$orig_h)]); - } - } +.. btest-include:: ${DOC_ROOT}/mimestats/mimestats.bro + :lines: 6-29, 54-64 Next, we create the reducers. The first one will accumulate file sizes and the second one will make sure we only store a host ID once. Below is -the partial code. +the partial code from a :bro:see:`bro_init` handler. - .. code:: bro - - local r1: SumStats::Reducer = [$stream="mime.bytes", $apply=set(SumStats::SUM)]; - local r2: SumStats::Reducer = [$stream="mime.hits", $apply=set(SumStats::UNIQUE)]; +.. btest-include:: ${DOC_ROOT}/mimestats/mimestats.bro + :lines: 34-37 In our final step, we create the SumStats where we check for the observation interval and once it expires, we populate the record (defined above) with all the relevant data and write it to a log. - .. code:: bro - - SumStats::create([$name="mime-metrics", - $epoch=break_interval, - $reducers=set(r1, r2), - $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) = - { - local l: Info; - l$ts = network_time(); - l$ts_delta = break_interval; - l$mtype = key$str; - l$bytes = double_to_count(floor(result["mime.bytes"]$sum)); - l$hits = result["mime.hits"]$num; - l$uniq_hosts = result["mime.hits"]$unique; - Log::write(LOG, l); - }]); +.. btest-include:: ${DOC_ROOT}/mimestats/mimestats.bro + :lines: 38-51 Putting everything together we end up with the following final code for our script. - .. code:: bro +.. btest-include:: ${DOC_ROOT}/mimestats/mimestats.bro - @load base/frameworks/sumstats +.. btest:: mimestats - module MimeMetrics; + @TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/http/bro.org.pcap ${DOC_ROOT}/mimestats/mimestats.bro + @TEST-EXEC: btest-rst-include mime_metrics.log - export { - redef enum Log::ID += { LOG }; - type Info: record { - ## Timestamp when the log line was finished and written. - ts: time &log; - ## Time interval that the log line covers. - ts_delta: interval &log; - ## The mime type - mtype: string &log; - ## The number of unique local hosts that fetched this mime type - uniq_hosts: count &log; - ## The number of hits to the mime type - hits: count &log; - ## The total number of bytes received by this mime type - bytes: count &log; - }; - - ## The frequency of logging the stats collected by this script. - const break_interval = 5mins &redef; - } - - event bro_init() &priority=3 - { - Log::create_stream(MimeMetrics::LOG, [$columns=Info]); - local r1: SumStats::Reducer = [$stream="mime.bytes", $apply=set(SumStats::SUM)]; - local r2: SumStats::Reducer = [$stream="mime.hits", $apply=set(SumStats::UNIQUE)]; - SumStats::create([$name="mime-metrics", - $epoch=break_interval, - $reducers=set(r1, r2), - $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) = - { - local l: Info; - l$ts = network_time(); - l$ts_delta = break_interval; - l$mtype = key$str; - l$bytes = double_to_count(floor(result["mime.bytes"]$sum)); - l$hits = result["mime.hits"]$num; - l$uniq_hosts = result["mime.hits"]$unique; - Log::write(LOG, l); - }]); - } - - event HTTP::log_http(rec: HTTP::Info) - { - if(Site::is_local_addr(rec$id$orig_h) && rec?$resp_mime_types) { - local mime_type = rec$resp_mime_types[0]; - SumStats::observe("mime.bytes", [$str=mime_type], [$num=rec$response_body_len]); - SumStats::observe("mime.hits", [$str=mime_type], [$str=cat(rec$id$orig_h)]); - } - } +.. note:: + The redefinition of :bro:see:`Site::local_nets` is only done inside + this script to make it a self-contained example. It's typically + redefined somewhere else. diff --git a/doc/mimestats/mimestats.bro b/doc/mimestats/mimestats.bro new file mode 100644 index 0000000000..b854b26c2d --- /dev/null +++ b/doc/mimestats/mimestats.bro @@ -0,0 +1,64 @@ +@load base/utils/site +@load base/frameworks/sumstats + +redef Site::local_nets += { 10.0.0.0/8 }; + +module MimeMetrics; + +export { + + redef enum Log::ID += { LOG }; + + type Info: record { + ## Timestamp when the log line was finished and written. + ts: time &log; + ## Time interval that the log line covers. + ts_delta: interval &log; + ## The mime type + mtype: string &log; + ## The number of unique local hosts that fetched this mime type + uniq_hosts: count &log; + ## The number of hits to the mime type + hits: count &log; + ## The total number of bytes received by this mime type + bytes: count &log; + }; + + ## The frequency of logging the stats collected by this script. + const break_interval = 5mins &redef; +} + +event bro_init() &priority=3 + { + Log::create_stream(MimeMetrics::LOG, [$columns=Info]); + local r1: SumStats::Reducer = [$stream="mime.bytes", + $apply=set(SumStats::SUM)]; + local r2: SumStats::Reducer = [$stream="mime.hits", + $apply=set(SumStats::UNIQUE)]; + SumStats::create([$name="mime-metrics", + $epoch=break_interval, + $reducers=set(r1, r2), + $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) = + { + local l: Info; + l$ts = network_time(); + l$ts_delta = break_interval; + l$mtype = key$str; + l$bytes = double_to_count(floor(result["mime.bytes"]$sum)); + l$hits = result["mime.hits"]$num; + l$uniq_hosts = result["mime.hits"]$unique; + Log::write(MimeMetrics::LOG, l); + }]); + } + +event HTTP::log_http(rec: HTTP::Info) + { + if ( Site::is_local_addr(rec$id$orig_h) && rec?$resp_mime_types ) + { + local mime_type = rec$resp_mime_types[0]; + SumStats::observe("mime.bytes", [$str=mime_type], + [$num=rec$response_body_len]); + SumStats::observe("mime.hits", [$str=mime_type], + [$str=cat(rec$id$orig_h)]); + } + } diff --git a/testing/btest/Baseline/doc.sphinx.file_extraction/btest-doc.sphinx.file_extraction#1 b/testing/btest/Baseline/doc.sphinx.file_extraction/btest-doc.sphinx.file_extraction#1 new file mode 100644 index 0000000000..312663e74e --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.file_extraction/btest-doc.sphinx.file_extraction#1 @@ -0,0 +1,14 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -r http/bro.org.pcap file_extraction.bro + Extracting file HTTP-FiIpIB2hRQSDBOSJRg.html + Extracting file HTTP-FnaT2a3UDd093opCB9.txt + Extracting file HTTP-FsvATF146kf1Emc21j.txt + Extracting file HTTP-FkMQHg2nBr44fc5h63.txt + Extracting file HTTP-FfQGqj4Fhh3pH7nVQj.txt + [...] + diff --git a/testing/btest/Baseline/doc.sphinx.ftp-bruteforce/btest-doc.sphinx.ftp-bruteforce#1 b/testing/btest/Baseline/doc.sphinx.ftp-bruteforce/btest-doc.sphinx.ftp-bruteforce#1 new file mode 100644 index 0000000000..35bb3fca30 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.ftp-bruteforce/btest-doc.sphinx.ftp-bruteforce#1 @@ -0,0 +1,24 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -r ftp/bruteforce.pcap protocols/ftp/detect-bruteforcing.bro + +.. rst-class:: btest-include + + .. code-block:: guess + :linenos: + + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path notice + #open 2014-01-21-21-56-07 + #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p fuid file_mime_type file_desc proto note msg sub src dst p n peer_descr actions suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude + #types time string addr port addr port string string string enum enum string string addr addr port count string table[enum] interval bool string string string double double + 1389721084.522861 - - - - - - - - - FTP::Bruteforcing 192.168.56.1 had 20 failed logins on 1 FTP server in 0m37s - 192.168.56.1 - - - bro Notice::ACTION_LOG 3600.000000 F - - - - - + #close 2014-01-21-21-56-07 + diff --git a/testing/btest/Baseline/doc.sphinx.http_proxy_01/btest-doc.sphinx.http_proxy_01#1 b/testing/btest/Baseline/doc.sphinx.http_proxy_01/btest-doc.sphinx.http_proxy_01#1 new file mode 100644 index 0000000000..d14ba4102a --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.http_proxy_01/btest-doc.sphinx.http_proxy_01#1 @@ -0,0 +1,9 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -r http/proxy.pcap http_proxy_01.bro + A local server is acting as an open proxy: 192.168.56.101 + diff --git a/testing/btest/Baseline/doc.sphinx.http_proxy_02/btest-doc.sphinx.http_proxy_02#1 b/testing/btest/Baseline/doc.sphinx.http_proxy_02/btest-doc.sphinx.http_proxy_02#1 new file mode 100644 index 0000000000..48f5d8719b --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.http_proxy_02/btest-doc.sphinx.http_proxy_02#1 @@ -0,0 +1,9 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -r http/proxy.pcap http_proxy_02.bro + A local server is acting as an open proxy: 192.168.56.101 + diff --git a/testing/btest/Baseline/doc.sphinx.http_proxy_03/btest-doc.sphinx.http_proxy_03#1 b/testing/btest/Baseline/doc.sphinx.http_proxy_03/btest-doc.sphinx.http_proxy_03#1 new file mode 100644 index 0000000000..09b2137d42 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.http_proxy_03/btest-doc.sphinx.http_proxy_03#1 @@ -0,0 +1,9 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -r http/proxy.pcap http_proxy_03.bro + A local server is acting as an open proxy: 192.168.56.101 + diff --git a/testing/btest/Baseline/doc.sphinx.http_proxy_04/btest-doc.sphinx.http_proxy_04#1 b/testing/btest/Baseline/doc.sphinx.http_proxy_04/btest-doc.sphinx.http_proxy_04#1 new file mode 100644 index 0000000000..cfe35296cb --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.http_proxy_04/btest-doc.sphinx.http_proxy_04#1 @@ -0,0 +1,24 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -r http/proxy.pcap http_proxy_04.bro + +.. rst-class:: btest-include + + .. code-block:: guess + :linenos: + + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path notice + #open 2014-01-21-20-11-20 + #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p fuid file_mime_type file_desc proto note msg sub src dst p n peer_descr actions suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude + #types time string addr port addr port string string string enum enum string string addr addr port count string table[enum] interval bool string string string double double + 1389654450.449603 CXWv6p3arKYeMETxOg 192.168.56.1 52679 192.168.56.101 80 - - - tcp HTTP::Open_Proxy A local server is acting as an open proxy: 192.168.56.101 - 192.168.56.1 192.168.56.101 80 - bro Notice::ACTION_LOG 86400.000000 F - - - - - + #close 2014-01-21-20-11-20 + diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_file_extraction_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_file_extraction_bro/output new file mode 100644 index 0000000000..acae92f44b --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_file_extraction_bro/output @@ -0,0 +1,28 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +file_extraction.bro + + +global mime_to_ext: table[string] of string = { + ["application/x-dosexec"] = "exe", + ["text/plain"] = "txt", + ["image/jpeg"] = "jpg", + ["image/png"] = "png", + ["text/html"] = "html", +}; + +event file_new(f: fa_file) + { + if ( f$source != "HTTP" ) + return; + + if ( ! f?$mime_type ) + return; + + if ( f$mime_type !in mime_to_ext ) + return; + + local fname = fmt("%s-%s.%s", f$source, f$id, mime_to_ext[f$mime_type]); + print fmt("Extracting file %s", fname); + Files::add_analyzer(f, Files::ANALYZER_EXTRACT, [$extract_filename=fname]); + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_01_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_01_bro/output new file mode 100644 index 0000000000..4e10859d98 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_01_bro/output @@ -0,0 +1,9 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +http_proxy_01.bro + +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code == 200 ) + print fmt("A local server is acting as an open proxy: %s", c$id$resp_h); + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_02_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_02_bro/output new file mode 100644 index 0000000000..01e3822001 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_02_bro/output @@ -0,0 +1,30 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +http_proxy_02.bro + + +module HTTP; + +export { + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; +} + +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( /^[hH][tT][tT][pP]:/ in c$http$uri && + c$http$status_code in HTTP::success_status_codes ) + print fmt("A local server is acting as an open proxy: %s", c$id$resp_h); + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_03_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_03_bro/output new file mode 100644 index 0000000000..5139fa8c49 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_03_bro/output @@ -0,0 +1,35 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +http_proxy_03.bro + + +@load base/utils/site + +redef Site::local_nets += { 192.168.0.0/16 }; + +module HTTP; + +export { + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; +} + +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( Site::is_local_addr(c$id$resp_h) && + /^[hH][tT][tT][pP]:/ in c$http$uri && + c$http$status_code in HTTP::success_status_codes ) + print fmt("A local server is acting as an open proxy: %s", c$id$resp_h); + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_04_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_04_bro/output new file mode 100644 index 0000000000..a8ca8e19b2 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_httpmonitor_http_proxy_04_bro/output @@ -0,0 +1,44 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +http_proxy_04.bro + +@load base/utils/site +@load base/frameworks/notice + +redef Site::local_nets += { 192.168.0.0/16 }; + +module HTTP; + +export { + + redef enum Notice::Type += { + Open_Proxy + }; + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; +} + +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( Site::is_local_addr(c$id$resp_h) && + /^[hH][tT][tT][pP]:/ in c$http$uri && + c$http$status_code in HTTP::success_status_codes ) + NOTICE([$note=HTTP::Open_Proxy, + $msg=fmt("A local server is acting as an open proxy: %s", + c$id$resp_h), + $conn=c, + $identifier=cat(c$id$resp_h), + $suppress_for=1day]); + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro/output new file mode 100644 index 0000000000..ef537b6c53 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro/output @@ -0,0 +1,39 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +mimestats.bro + +module MimeMetrics; + +export { + + redef enum Log::ID += { LOG }; + + type Info: record { + ## Timestamp when the log line was finished and written. + ts: time &log; + ## Time interval that the log line covers. + ts_delta: interval &log; + ## The mime type + mtype: string &log; + ## The number of unique local hosts that fetched this mime type + uniq_hosts: count &log; + ## The number of hits to the mime type + hits: count &log; + ## The total number of bytes received by this mime type + bytes: count &log; + }; + + ## The frequency of logging the stats collected by this script. + const break_interval = 5mins &redef; +} +event HTTP::log_http(rec: HTTP::Info) + { + if ( Site::is_local_addr(rec$id$orig_h) && rec?$resp_mime_types ) + { + local mime_type = rec$resp_mime_types[0]; + SumStats::observe("mime.bytes", [$str=mime_type], + [$num=rec$response_body_len]); + SumStats::observe("mime.hits", [$str=mime_type], + [$str=cat(rec$id$orig_h)]); + } + } diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@2/output b/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@2/output new file mode 100644 index 0000000000..027eade4dc --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@2/output @@ -0,0 +1,8 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +mimestats.bro + + local r1: SumStats::Reducer = [$stream="mime.bytes", + $apply=set(SumStats::SUM)]; + local r2: SumStats::Reducer = [$stream="mime.hits", + $apply=set(SumStats::UNIQUE)]; diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@3/output b/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@3/output new file mode 100644 index 0000000000..e410c6ebb9 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@3/output @@ -0,0 +1,18 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +mimestats.bro + + SumStats::create([$name="mime-metrics", + $epoch=break_interval, + $reducers=set(r1, r2), + $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) = + { + local l: Info; + l$ts = network_time(); + l$ts_delta = break_interval; + l$mtype = key$str; + l$bytes = double_to_count(floor(result["mime.bytes"]$sum)); + l$hits = result["mime.hits"]$num; + l$uniq_hosts = result["mime.hits"]$unique; + Log::write(MimeMetrics::LOG, l); + }]); diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@4/output b/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@4/output new file mode 100644 index 0000000000..0e97a0b14e --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-doc_mimestats_mimestats_bro@4/output @@ -0,0 +1,68 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +mimestats.bro + +@load base/utils/site +@load base/frameworks/sumstats + +redef Site::local_nets += { 10.0.0.0/8 }; + +module MimeMetrics; + +export { + + redef enum Log::ID += { LOG }; + + type Info: record { + ## Timestamp when the log line was finished and written. + ts: time &log; + ## Time interval that the log line covers. + ts_delta: interval &log; + ## The mime type + mtype: string &log; + ## The number of unique local hosts that fetched this mime type + uniq_hosts: count &log; + ## The number of hits to the mime type + hits: count &log; + ## The total number of bytes received by this mime type + bytes: count &log; + }; + + ## The frequency of logging the stats collected by this script. + const break_interval = 5mins &redef; +} + +event bro_init() &priority=3 + { + Log::create_stream(MimeMetrics::LOG, [$columns=Info]); + local r1: SumStats::Reducer = [$stream="mime.bytes", + $apply=set(SumStats::SUM)]; + local r2: SumStats::Reducer = [$stream="mime.hits", + $apply=set(SumStats::UNIQUE)]; + SumStats::create([$name="mime-metrics", + $epoch=break_interval, + $reducers=set(r1, r2), + $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) = + { + local l: Info; + l$ts = network_time(); + l$ts_delta = break_interval; + l$mtype = key$str; + l$bytes = double_to_count(floor(result["mime.bytes"]$sum)); + l$hits = result["mime.hits"]$num; + l$uniq_hosts = result["mime.hits"]$unique; + Log::write(MimeMetrics::LOG, l); + }]); + } + +event HTTP::log_http(rec: HTTP::Info) + { + if ( Site::is_local_addr(rec$id$orig_h) && rec?$resp_mime_types ) + { + local mime_type = rec$resp_mime_types[0]; + SumStats::observe("mime.bytes", [$str=mime_type], + [$num=rec$response_body_len]); + SumStats::observe("mime.hits", [$str=mime_type], + [$str=cat(rec$id$orig_h)]); + } + } diff --git a/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro/output b/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro/output new file mode 100644 index 0000000000..59d57223d9 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro/output @@ -0,0 +1,21 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +detect-bruteforcing.bro + +module FTP; + +export { + redef enum Notice::Type += { + ## Indicates a host bruteforcing FTP logins by watching for too + ## many rejected usernames or failed passwords. + Bruteforcing + }; + + ## How many rejected usernames or passwords are required before being + ## considered to be bruteforcing. + const bruteforce_threshold: double = 20 &redef; + + ## The time period in which the threshold needs to be crossed before + ## being reset. + const bruteforce_measurement_interval = 15mins &redef; +} diff --git a/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@2/output b/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@2/output new file mode 100644 index 0000000000..648fe8a559 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@2/output @@ -0,0 +1,13 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +detect-bruteforcing.bro + +event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) + { + local cmd = c$ftp$cmdarg$cmd; + if ( cmd == "USER" || cmd == "PASS" ) + { + if ( FTP::parse_ftp_reply_code(code)$x == 5 ) + SumStats::observe("ftp.failed_auth", [$host=c$id$orig_h], [$str=cat(c$id$resp_h)]); + } + } diff --git a/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@3/output b/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@3/output new file mode 100644 index 0000000000..f81c9f50ba --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@3/output @@ -0,0 +1,27 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +detect-bruteforcing.bro + +event bro_init() + { + local r1: SumStats::Reducer = [$stream="ftp.failed_auth", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(bruteforce_threshold+2)]; + SumStats::create([$name="ftp-detect-bruteforcing", + $epoch=bruteforce_measurement_interval, + $reducers=set(r1), + $threshold_val(key: SumStats::Key, result: SumStats::Result) = + { + return result["ftp.failed_auth"]$num+0.0; + }, + $threshold=bruteforce_threshold, + $threshold_crossed(key: SumStats::Key, result: SumStats::Result) = + { + local r = result["ftp.failed_auth"]; + local dur = duration_to_mins_secs(r$end-r$begin); + local plural = r$unique>1 ? "s" : ""; + local message = fmt("%s had %d failed logins on %d FTP server%s in %s", key$host, r$num, r$unique, plural, dur); + NOTICE([$note=FTP::Bruteforcing, + $src=key$host, + $msg=message, + $identifier=cat(key$host)]); + }]); + } diff --git a/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@4/output b/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@4/output new file mode 100644 index 0000000000..bb7b0fd078 --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@4/output @@ -0,0 +1,64 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +detect-bruteforcing.bro + +##! FTP brute-forcing detector, triggering when too many rejected usernames or +##! failed passwords have occurred from a single address. + +@load base/protocols/ftp +@load base/frameworks/sumstats + +@load base/utils/time + +module FTP; + +export { + redef enum Notice::Type += { + ## Indicates a host bruteforcing FTP logins by watching for too + ## many rejected usernames or failed passwords. + Bruteforcing + }; + + ## How many rejected usernames or passwords are required before being + ## considered to be bruteforcing. + const bruteforce_threshold: double = 20 &redef; + + ## The time period in which the threshold needs to be crossed before + ## being reset. + const bruteforce_measurement_interval = 15mins &redef; +} + + +event bro_init() + { + local r1: SumStats::Reducer = [$stream="ftp.failed_auth", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(bruteforce_threshold+2)]; + SumStats::create([$name="ftp-detect-bruteforcing", + $epoch=bruteforce_measurement_interval, + $reducers=set(r1), + $threshold_val(key: SumStats::Key, result: SumStats::Result) = + { + return result["ftp.failed_auth"]$num+0.0; + }, + $threshold=bruteforce_threshold, + $threshold_crossed(key: SumStats::Key, result: SumStats::Result) = + { + local r = result["ftp.failed_auth"]; + local dur = duration_to_mins_secs(r$end-r$begin); + local plural = r$unique>1 ? "s" : ""; + local message = fmt("%s had %d failed logins on %d FTP server%s in %s", key$host, r$num, r$unique, plural, dur); + NOTICE([$note=FTP::Bruteforcing, + $src=key$host, + $msg=message, + $identifier=cat(key$host)]); + }]); + } + +event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) + { + local cmd = c$ftp$cmdarg$cmd; + if ( cmd == "USER" || cmd == "PASS" ) + { + if ( FTP::parse_ftp_reply_code(code)$x == 5 ) + SumStats::observe("ftp.failed_auth", [$host=c$id$orig_h], [$str=cat(c$id$resp_h)]); + } + } diff --git a/testing/btest/Baseline/doc.sphinx.mimestats/btest-doc.sphinx.mimestats#1 b/testing/btest/Baseline/doc.sphinx.mimestats/btest-doc.sphinx.mimestats#1 new file mode 100644 index 0000000000..8396de608d --- /dev/null +++ b/testing/btest/Baseline/doc.sphinx.mimestats/btest-doc.sphinx.mimestats#1 @@ -0,0 +1,31 @@ +.. rst-class:: btest-cmd + + .. code-block:: none + :linenos: + :emphasize-lines: 1,1 + + # bro -r http/bro.org.pcap mimestats.bro + +.. rst-class:: btest-include + + .. code-block:: guess + :linenos: + + #separator \x09 + #set_separator , + #empty_field (empty) + #unset_field - + #path mime_metrics + #open 2014-01-21-21-35-28 + #fields ts ts_delta mtype uniq_hosts hits bytes + #types time interval string count count count + 1389719059.311698 300.000000 text/html 1 4 53070 + 1389719059.311698 300.000000 image/jpeg 1 1 186859 + 1389719059.311698 300.000000 text/troff 1 1 2957 + 1389719059.311698 300.000000 application/pgp-signature 1 1 836 + 1389719059.311698 300.000000 text/plain 1 12 114205 + 1389719059.311698 300.000000 image/gif 1 1 172 + 1389719059.311698 300.000000 image/png 1 9 82176 + 1389719059.311698 300.000000 image/x-icon 1 2 2300 + #close 2014-01-21-21-35-28 + diff --git a/testing/btest/Traces/ftp/bruteforce.pcap b/testing/btest/Traces/ftp/bruteforce.pcap new file mode 100644 index 0000000000000000000000000000000000000000..46bdb569d739b7a2a9b3b0990b76180f0545c69a GIT binary patch literal 55167 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 TbxzEvsF&~Py~cgV9Tol$)Mgjz literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/http/bro.org.pcap b/testing/btest/Traces/http/bro.org.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a50be129899f85de3c5cc137f2ecc930aced3286 GIT binary patch literal 506533 zcmd?S3wUHnbtafqK%3II>|VxWFrVGNl~pZemh!2$GL@>9s#K5edWe#mE?iv{SD81Z zlv0^lc{BAWmB3GIuxZ|YG|VjE0l!$r1K8&C*t-mPji2iovxc>e8Gqwl<7Q?6d+hPf z+U?%|oD*?x+{~M)s_tg+_n~f;GVhHzapJ^@b55LdBI5u2YPzicu@v}qoA6h&F=wE!zOP+b=ug3+lVEHM)ngAU7)lfVv zV<*0cv3zX@mR|(C!;AM%zxemRC{TXsBS#|_&~f_hgmNf<;(H0oo7O|2ylnc#zfg@t z&MhokY3uy*@?tuh${rm!Uw2zMYo%FF)tjqF2Of2uW^!)Tso~+J`t3@!YNy9j87p=z zo6TDnE4B8HRhgKY$Xm^=+{joe6SvMe#f^G;B$LhH|EzVk(sau8oix2XIxtr(It{>T zIXkWNT5GeKup5nPrD(S*^;&v|o(%7FKHaS5Zxu4B>BPzON&YmY0VOZmwbi!0>f|h^ zmV9(6;ncXmxL07IR;-sQwbh)pdb`p{SS6=iwOh{7fz$O`%_&l|Icvjl8cDla*~0Uq z12oj1{Aiz{jy?7_Jk$dnLw)$Er+?$=#rvOmX5ddTs{BK+KJ=w;ihSZl5&rFDn-_ib zvHwP}-nrik)@n2o(ZgenWHQ#3M~)7hK^Jn?a@$E**)i*3yM{OTke$qBrgI?rxl7AO z2bP@Xmeb5xa}B$==A=hbW2p%%cGfA?n|A!@z(w0_B`<+E<%&}Z12&P%Oy)*L1=zx} z4H`yAo$=}9m{TriCPqg~6Jy0p)Fbs(jD_QZd3IZl%LHzLZ;}_C+G=YpXJyByC%|Bj z5UuBk*5HE5rc-aX3gZcD)7~k7V}j%2m-WFd?>4BW=AXP(T(g_5(<(f=d^QQjI65#e zbL`BO)61_~T(F3rW(Q{Ij|H}>xrOLjtJTP*)7#tIsqIl>@^p53dRka7N@X3pG&^A7 zXQowYRh`-8HOHE7)~(A zE^3tAs8y`jh!%xt)JiMhM!AyX7Mqm@@!~;6oAs4?%LG`dm7JY~Rjya7_3cpTtM&S7 z)k(UQmXicOV7O(r8BMJ`GCg+rmFG9h+%B$GcN+Ej z_APg-*x3Y8GwIxFSGEdK%qSjk8X*ICuc2aOg=W=CZNq9h)k4%=t2bN4cFU@OWKnAk zvZD}9rOWmfJxJl7&T1{RR)}&VMHiG2FsBjErCdR={anVhuRI$-! zvFSKyOpgp>b5CHWCo(-C&Kyf7ty%xLHd1H3wUNEPjs5lb=`2Hx&9J}t+AeL?r zRfIvhT9XN5xy_EIvOs3Y| z=wMu0l)DZ>L^}oO$eTNiRJ4pM!eg(I;5PyzH50zU5>j!crsZQ^AE`v)An%A_Cz# zh8FtZ`TdONUI?B)%Xt2j;8_KfKKkqbW&O3+f#=U^T^M~^Bm((kH!9#!3<%+uu2xpu z^!lx~)7*vGF_s!rUs9WuT5w!s{CkXr+5c2}U4u*&cZ*dgWml`u6TGrrEAFn;caquE zD6oY--FP0bY;8k6Jr8hhH(j?3`SLt~YS}AQr(Ra-$|Z=NevP(U<>ZtxWz^if+p%%m z4X0VIxNFY^&$T)x^99y39boQ_QDD(JO}p9wgXcYDjV017Oe2XnsBFUKOs`hTzIx$D zuBWN^U3%8?W!Q@CI#$bWuEJJ{-fY-SC?Zj2Gifn8SXo>tm8!c5YuoX3MjQ3E>}G|= z#MZl`VYT9tP<5p|U*|Z>^Dpe{*@9@N`)QZ)1395(Xp$wRH)~>p$)RLvMQxQlr$5pJEsXAs@g7WFU(3CEU*JR zOMsD;#q`#7TJ^??9a>=~jWR+{8YcSTs@xkUvpmFO4UDMTr*$r;F@x=5SHKfDvlCIq zUMeSPD)0*vXIPlYB=;a@!SrlleF5QCUcI?et*_o}H>(Mai}!bEsO#C#JW897V{t2< zP+&{-VzXXvS+BK*(u_l~m1bKnMaHaG%YW%VI!!1STiyc!E5mdwNqXUSf4%SntQT%~ z>xJtRi}zpp=?}j^^up3t`s#)M&U)c?P%m7c(0bt&k47R%OLa3xbV~6k@}T1JYO~&M z&~u~PfdU{iSF=)`B?e~NRn2m4ISGreZQ*at-Xh)-F4Y5rnLayXdxoY@;^^%8`ld6J zwxztsuil3lXfcD231A1XQhmEtt=lC7zv%24_0WBepo?v?WM$oKVtuA=ym?M-Kwvju zjR&w_l4s8eF06pfHkMAi0m!HI)8_=cL?72$otJoqMY&BsK zIn5MWqZM^@_JZrS9cx)0-(A}Qn$M(Z7&HOA4+l@VrsG1z6xRY|zp5T~kNiDA?iRw) zStV(o6I@!CZ`zFj!b^B&U9uYo1NI3e`f&i>4_1_Z&$Koqb-W2x7N(6sY0?WNNc2AI zh1auQ*zMK}uldB{{ntMJ-kYKq-rZj>{C}($c7uB1HJ{LW;l?{75k2s}DktP=1lVTk z*4ZPbcGk5`{l40)lx|L2cD1o)cW3}A?orFDD@5#muBqu(N)EJ1vQ;m3AtsH5G^3$+ z{_Sdp3eZqiHdj4U%Gq^bjq{3E*_uQYdYWp~R-@<}?8k;Jju4&>4A1(3|4!JODXr3kAhEpVOnQO@xvSx=7Hgipa=M@obW>c5RHaded%S`{ z_TNgsxpA>UYm@NQXQ)`!e@O%&O{eg5Pv(jl6E6kJ1dUZ;sV704uvgW|CZHiVr zFr+HIhQZc%U;qZ>g!ppF+wZokv?@#xvs7yQiH4=vc3Y5ZhLwtFi9bTLWQQ}_MpVJ2 zv4J>A4c1oNM&9z)C`SAOLL9AV5Vaa0La@&v-J2$f= z7Y~w}+{OWd^Fl3ILdXdO#tr$VxCK zjXN-~?ZA_6J%)cR^2#9M2<=aL;YnAzIJ5|HI5hKN^#LYFlg zeR12!K!CrzO*YC3Rt2kM6hJJPT7A`SSO^rsKVO4RgcEVIVv|}O7!VtW`knyReb!2E z;J$Bl_r3Zs_5F1!wo(F=KCzXjSto7<`(Axm>%>R?TO>m42Q!4svr5Y)k1vER%_(cS zUb5jyhNOV-gD)FleyiO82L%kZfq_cRG>2ApMb5fxDzg3R)G!0;HIAGz>j>+C9YMHC zb6^0$5d@ZNuB4kcPc)uVbFU4aC8@77X0PzIi)r{Db#0}m>5x*o2Qu=4oJSFx_+VN zVjTxBJ1KsU*P2(=6V~auJd+Boff(AyY1j|7qHCv+(o?C`5uD@ZE_*F8v1zo?7DaCS zahUTncG!tYtv=dZfv!%TUb8nFHf&-H=7oz8>zzw9(njWwUc8yl=yTWFebkeSokhKM zty=kQ)0}Rp)%VQWs9x2{bG7JQVz~f4J=zhpD7r|M;Fn2~l&}gZm7owsZBAmzWFE{% zXD`C53zpQ_&!`xf7mg+`9A%hDFq%Da>n=i|QL8hYEFnxk4n3e@^(aWL3I&y1%dsIr z7S8^mEdJT^R+u?!$f*tO$Mb##getDo2=&vL2P<&d#mem(r$8Y@u*U`?;!Mg&6$+ik zL}=ElRskAfTQ@9CrcSdl8z>hW%4EkUvf0te?DY89^!R9IYIJgJI=6LuV|#U^R04Yp zF-BHcD=8p&)gjY)$!RTBZaXp6Q`Mj}l{$Oj;_|}Pg)=u#FD=}>y0G-<#pR`iWd)Wx zP-g+?h9Z5YX>VVV_c2vP6;H{UTpB^J_e!n08#B{|U~Y51kiv%IFwuCP*pW#G4NZFC zR)4+lM%D}MZoP2pGmH1%esNvJR(`U-Uib&r3+kl*5+erSR`9ZOy3%U2%ejNu(Mp;pPP$sJZ={iQXJb?)-@{;R z&cY$j)C?CkCkMU43sk|fX4NewSDKKdm~)ANz*pwmt%_S&sZ_CY&0#H2Dj^GSV4oBl zGzXWKAxo~bTP^56Vf9ToB;ci~I%VV|PBwOEqF5HHq3hI7%t>*4nX>4vgv-JfgeO_i zTDTlTw2=HnM?5K#E_ZrW?@V0|MAvOg?K$JX~L~ z$U4WkDS8}v%(2#NxE?%Y((CmV-8gA=c)Z{xBD01%O&xib!|+NtKVGe_3%6pc zy(0NSWUr(zHJ7Rg@K>uc60fSam+_u5A&@hQ)!lPKi`k4=jl#b~2Bo)Ppsac6YD!B} zJXuFo(v;(Y6gDL2x_U;zD?u(|);kD;QdR;otH}SrrIYkAnH}57B5B3*5nsT=Xd3LT zLYoGo!dJ_Ydo-IwRtY&hC=m0khrsLWGR!0xGT!$Yw*gx{&~v4+i8A!#@rNQsOCYc= z#q_ude{gj6A@#}Y3)f5&aIn36@n)gB3ALxxy+?Hgme;8ebVyt**)2O+qGU}Hg-Gyl zXkZG_(eX@F<1cxMTKI*bCSZzdaAP|K(hL8pzh3xZ)(fp}y|BHqc>fPruf8d3rO)-( z3(v4#Xa)7c_KMaEKlJHHBwDLWY6Gm;GBONcp4X66+C-)VtX&9M5RX$+bYGbsBKMGJ z2s&gllT)MFiIL3s_~dkEd>X-*WlCjo$&~II5oOQJ9`kICQo>DCO7T5X)$4AeyzUlC zDVS^vRfm@t^Sj73zKqn!m>a*IxshlT(ytaKNWppBij`8;x}>niPYuzFp&b8lhw_zj z?3f8_e)mEthPL8++z9*D9Muk>=aDanE>%kOfhJL7I10;6FOyT|zzPL8B`Ob;kpxCm zx=eY76*v%@t$C!mH=UUDD4yTnk0FbJgY*eXF-3lFG!fP8wvEiHc-~jCidPkjdh-p6 z13{53JyGsT`{;4AdWr@u?^q-NW^1j0MqJ+D|Bji%emxH z6P0+BOoBob--RgAET+7lT?x+EZ7Ch#Y_1^Tj!<8PP(d1Fs_$?y-Cp{xT}HB+r@IQny`;+kKPXRQih4(w8ltl+JHgj_jmVk!e;iByBo+EWi= zncOS8F2N(=!ryIZAs9EE(w`V6WOW?E;!s^kh^B=!v$x{qhFy|fAR~;to=_%ppI*8^ zVN&L|u;!~PRjlW>LRBs|N(Fo^dvX5qMUQqpnkT*RRDZqjBdizPZoP2lON;lv@q)z6Ov7a8p_af5o{&X=@a_}F$NqRbCX01CB`$r?t95WhjMf#9M(Q7)fenmdRn zGA0_2Ft>$U?mrMU6j*QQkoe`Lvj;V)`mSa@O?oXG@L6L5iilh$;bZ{6)usd~2O;A~+rg4si0%QQmj^24)fm|(G z0CJjUAo1t4Ji8}2;PwCvT05SGX#&FzuE>QQ`0iR2m;HlxiJR&lk{GIpp>@mMw0eW& z12`WM#!0UrodiBkWH(ZHnf%L0U&4YMUfYW(b5H#_IBW7Ay3r#Y&bo?xW~?&d6{c|4 zU5}cg49w(bo$nUlf*zD6y^w-L?;RDnh7F&HiaZgN=-+#rB|4%ak#|QTo)R=+RfgdZfP|I?Q_LRtMH!)Ox5n6^T%)k=KYZ?^!U6bxd_ra)?BD z_JToj+LhJ$oaBS)+@bg<((aIMQFD}sWf|W8WeSU4lE?SXf5=9$VRD8TL)p5B+@#0XG=Z2B24j7d_5U&=bk7^Z$@tUuLL?CyF~r`q=`-%x?&+L~3&;62y zymco4`N!$G#`&pl>j!!C&k6GDUgSX@jx2us_P=|rhMYr=wt;g1^1HsHALRSi2=WKN z&x4$dEdKCI{-3XC$lvv)-jKfo-pSs%5ZAsn0?6;Y(ZOkN)3(FJzd$a;-5c-3;nj-0 zNl_)RBfD}C*ToYH=NQnVgQwV1vEFJ~SKAa6fEuIiKw89^f63yTv)wgpeYBP^n>X$L zW$$Xqot~rIut(kWqEl~F9le@hHxyi&>uzP+*@(_QjI;qxi&>)Y2X`r~ZC7F;aC4Ti znFM*zo0bZXJUe(=ai(#Y0k$K|UZp?Q5+`atJBVE>^8o6=yT3-6e^{^BwTe@CO>L1Eka9*+NY8?_zNB7QuhcJk1MjIYH4|xl>2a57_I{P^;z=xK$x1rP|D4Ry`aeI!wr%Lrx{NZvN-qj|&o}(jEQ`6B|&-~Gr+gVCN<4hIH z;u_Z6=?h6!zBi%!Xx~&{%udZcb_M~bLUwd)Dl<8G_ZUg}-Wc8O&@<-ZL(i$7Y0MxwB}J{DQWj~>vykY0a^#*MUGc;% zPgn3!Omt4d6Avuj|E|TX3ta&y`+)LZtas_RGe7Xq+pj^tK6Kwtbex~_!~@y_`NHW) zLD11^0e4ImcA8i8Cq5E4ioTckluc{5N31pZM?J$~TP zM;wa5jimsJ6s~})MlDdP$UQ^gR@lUVsfJoN(KYM)3{WQm$34c7Pzd%dHIR%%2i#!O z5WE?B$M`ay&n{o#?s5u&*Ls%=Q_!19%hqp52s&(s2J8p>4?CM;Pc*uR{mpM!y#GC) zJ4t2@pj1B-iJZld({HCicWCOwTZnnybTbsn%ii<37yVatwiTTF9eOO zH^1Sjr+@1x9c=Ym=gE+xAA~72xk7r2&3EYGBLUz zuzJ(ze1QSuT7G@ED_4Eeb{x{V}o_qdztk-xs6z zKSCHC{iuhLER8-7c#P2paOxiMk<%ZeV~o)s85qUpf9d6iuzdSA!sws;h>20NFGdfr z)ObhT!$_8a-v)S$(H9>QjN17_kvYg6`t6cEqoaR8{d(;;dQi-<$GLi6i5ap-oelMM zE_QM=eWpR|8qT&XwOGkwZVkE`JJG3m6#s?HZiP`_^f2e(v?& z;FzKUgOmRQV{j;Lp$^abIv=377Wxj*aULL3PLV7>{KGH#LWBmW@~bjDGC+&7ha#sj zIP}{!K;sX*l?LeTwl_fL9K-;<^rOZAdFPOQoe$5aK~hrLJ=FFI9v)L@lZZV0>DoUG z((pv78voGzdG)D&!tMPRX?VWzr@i4Zg*Jxg&)_BELqmct$V2pphKWID*x{e~_y>QJhUl%xvXLK}KP!KKsGpy5lwiH{ zAp;hU0rpMkFaPD&@I2QkoDUl~&vj+0q>ghPFRzRh$L{_(*OBS*$-bw#PEQBdA_pAi ziUkrK-kMs&F2g;GcBjZ*L!7RGe7Br+yo{e>krMP%MU>EwZT`t)rxMPZ z#Z9BsU80w|L>tB_0a?Ll7%;|)$hVygbSJfl6WN;eqAHy=O5bgZOK|I9Ybp1u=o$c| zV+T?+wM6GzU{e}HSS=Y4Y@1*R!sqCuy-G2427B7*00t@TpmeVh(=`@08*8e#Icj0R zjUifHGY}y(rZTE4+nmUa^NH)#QV_TENPnW}t>9J(0HEfArLpA>!F8`Ib))zc{{)L) zX}91}Qn1Zo9p|55VYtsW8@ezJ3KOX}=1bU}1Cw8 z;NTlLjF?y(=2RqVcg% z5HcwoR({cS+NHWG489_X{@wj0I+nbU=%<1b{hj|zJ4FV65GNLCaTL}hlFsNTZpHf> zCW(n)og`bviN=DTDM&II98*0l+;S0l6Lfl|ILf80IfHF`d|Y#_E(=caM!9AiM9n(W znQ~bG6ERbBEfmF8DTPFB#VBmz%Z2CL6*}ocaHs{jf%qrSM|C4P3>#$GW1qvOU+gtt zQO5$B!JMW8A{7vGLYXWm1q1wqjle#4n3Ipof|;mMExc>y#Gayo>Ma?#{sICzIJ}1W zs#Z2yA}VP5a!EumM#i=A6czSLvb9wKGUqAUC(jI)fxEK)eD0Qo%rT-*%OtQY^L&eBE$fxj7) z-aV_FcXm_-b5MKFkrcVwSCQ|=gSlz4Sf5H)u-BU_xaJ(_J-brmNvBAHs%1`xKDDrG zS|R3|{M@Go4tZ2fj2L6rw?dnag_X{b^40RHPn`v~XlqG?(Dhx_IS;2aw!Nr^%(3ay z5Qjl<&XuaQb9YT$!FE1PHq$=HkVJn161}&p^aQ&go~U`tD2_b+*3tP7J^5Y=K|HW5 zj*MRglwZd}jD9K{AwpXOaq24AQSq=FG~as3 z?v!b^YWeN)G!Da0G^&MqRb^p3yiT4L*iyuaQS)h~@4?zgDM{DV{XH-ppT-Pxy}{_Xo| zQT;3b++0+@X7zBtMfD`XdgqJ*E8u?|+5X40sGi8IJnL2U*yIE*ukqK)&-s!RwXPl* zptbPQ5;EU$%7T@&&froC9F0d8Qea~=PKfaqpL|=&o@_?TW%7FOQYJ4O4o<3(VaawP`gw{GY(#2!*jyAg$MKyO_oY%9-rIz ztyXXq3KDvdTY@)qfCrx0D^$M%Gj61W3~sH2V+>`P8_jYr!Oal1_3 zSR4l*;aH3u_5(gBCCc_@rMjEbMUaXL^8?3j!T+&Z%h8eZG_3jk=cg0cElB$Ub3BB? z1vqg84J6g(z-($f@4Iet+hh>t_nG9@p0E%3b9fI^&ULVd7RQ_^zQTE#b`eVy;xB)6 zco3{Ty5B{0iuQ*|=hd>fM#ocD^RivFR)-7aSY?w=uEw%cHLgd~+UuauCQgf}0!5!G zb1S@$*W}ZjUFH$K<-NNlkE}h~!~^eAZfMAa0sgf1n8n>3cArM07y#m1O@ka^ncvUx zv0m0568VUT)Nwk@W?q|MGaG&P~YStS2nB zwj4aWo#eB@b6GwR!-E?<0z*=Va@L5m=^cX6qg~1d5y_wuj&fE;*HS3ai5jG4w;<7b zn_%~CkedDAJ3JGN!*pMW%ztF^3A%jb*n7nUdslzGFvWTyAJhwzPw2SR>;D=Dq2#P_ z+Vsh(IvPjLk1=0>^4w*N1*}Th6{pRM(a}+4s|g5>~iNu#x!m{2q6`{8E<7$ znQ_fVMl;=zvwTns6~RQNOMO%klVUu!T?EfE!HK%MW3((MrU(pzh0Y$)Tb=Qln!CHDfTun_lg0E|P(}{;GnbjTC?H7whg(YvahlYY+V=guLM9>akfy_s& z;Dnv^lz*O3=tnx>K&lcgA2Atg4i}R^y`FcfTMp?S=scVufitv-lT=aWitKn7$B%T4 zi8s}h`C&0Lqv;+71)h`rur|W~j`F`a^_dI~{&&KHtIL;`BrItMIFGW)o8%J)w#-I` zuZra~@c>L6oK7V^9`9 ziG)OrQ3X=XedaJ`Fc}*m_>?X^76hK1&@aY2UhohRd_vg-#RG*GSV4wUlPZxUIAX|1 zp`M;iggfblpX{#}s;n2@-mMo3FQ>~#?tfbJ!qi&d^};mk1#@YR^+Mt0S})xB#YiM5 ze3`OGJPUW=h+;sKW6(!3GO?USKfU+NPaacg1w)fLH>SC_T}`>LNyv(<>yH3J(!zto zY$>dXhJ1r0&={fPL3P>r4`wTq7?j~sHj(f%;E=^^zLyA@1jv|`aL6K^vi#@BYvvfHh?JX3thRPgNz^;9WePd=*0%)}{A52&Zw zIDu)Y1t?vrnA~pKP=d<#qdDQB3S$p`)1Z{X<%GDj5xVL!j&jD)i1H2BPS$I{7`030 zpt4D&hg4pce2``|hU?;RU{vQ4G@_V=7S1`Sl&s^W z5=1(RfiVT9;osp#WCPm{Ed4j=FWVL2_5zWgDAHr} z#SqekAfDl5fCv#*F%8*u9I#m_@5;acpjW6vG@9&$WsEo^tdw~~2D~G%hkCq&LbJ{J zr6*2rNHWL!!RsdlI?<5c>m{u>ll3$TM}vvcRY%Fvjw)y%M`xHMu?-)we{gZf>=0$w zQA;oAlpON~%77v*0g|C$HYdGIh9yQy6-eko@Id*qM-2PG+9RtCHdQ@XE1=oMQsv{? z$jg<(wOlx&7w(?C*Ehx~t8g;$)QTc(Nv=7O!Nz$rOoESa@ z%$5U?f;MB|Rrnz4f!Ad2Gu1$A->G4eEnzaWRv3C*$QP3$+r(gn9A=TlQ>@vBJ3?2_9x=xVx(di9KN-8-K5s)*Q2Y{>hqdu$L;Um@>AS;2B|wQ(L^*Gqqij5G4!J(U8wF{8I$Q{=9q%jRXdOnTw_ z`|E`o>xH*=>xJ_pbot1akxfic{so})IZh={dg00Cpk6pX!g>LrykErr5<-!P-c3S} ziru3~mDE$MaGAU5d0!-nS>vVY&}-1oPH^!U+b?Ekr#>B%4A31-=}rr z3lOL2(QBHR)DvH-SyK(L2$4y7MiHi@B5KHS3%u^Wu}<`@FO(E&!5OIw5-^xmm7-i& zCGd&wHYQcL7=%izt8C1U&=8E^wZ6B&3p2Pp?D5i)&Kqu5zce ztE@+pz(3dlZ?zl1gc&>z>P5bA=~6wF{twTE1^Uz3}G-&AAmi zH#S+^ELoCX9Q2ha1j5&Y#A`kXb)T{ZLoYRZo6GDTVnqni>5zxr)JqnIwoH2A_xtOG z2J3}4ck6}ADY|^*^Y0P8@YntILV@+dL{KkWPHDaHR_xz|!{Vfx1A6Q{{vxVTc%xQ_ zGnBkVVUtD6w2sN*J;oY_uU+s5*rY8_txoze^Y}x?qs|^Ib`U9E@CH)9>4_X54IG!) zF3RYIgXkxABYQTE9|iEjZg41|zF(afCNS9L4E>j@3SGYa%Fa zom{0W=wK(sz~_h&3KVN9^B{fUA1K<)gSedlfDx-fNRxAox?rm1xCc+*Q?wk$F$3pM zGXE$Zk6e7L0qTtyHKrPl2VPLac*8$&!9ZG}BqTzhjEqs*xs3ev)k-OM=Gp~1w;YMZ zID-Lenbf5U@&Md=8Atc)ZXy8MY@MdY;qxpEsdk6x3b2y-m>WenOVy)H+Cs(>Br2T# zMhM)l*EeB_gp3WSrQ{|H5MC)MZxTQgr-`$P-tsab?4=S`9ric%zKa*`R=$~1_Ba~H z&7&-iJ$A&h)9}oMtSv{`Nk9mw>VXx%j208bD*$E>u&SO{9srsSJR8FTCc4ydIpu=} zmdYFASqC9>NxaoEM6cKMf*h~35|l+YIcR10l(R$hu&&Pz3>xV`2N)_nB`QcgV>6W)@!91oG?(sX|l&hR_H%- zm^8V2`iQ9y-+|Wq_yL>Thc|`v;jg$4>Lh>*&K@Y2Eh6U%;9N1Frdm zMz`ncT06J9dCHU)u)UP97#UG&Avm_3++^@BuDXw_EK0557S>7~ za=Nj$8?gDbWFtvQCMy`#G&tGQ)yoV7_9PitdAp+2!erQLN$jvOJ$u7#g`^H)W=BS%z>)ugSG^d3Oa zht#^4qs5-SBeE|Z7Ml%E zMkqCiED*LKa5*Yv9^y=5L>sBkxK$T7n$W>BI7SP%?#6I?EiPw6Brz_^((8dJ@>9m*Y-^rg0t6ks~@aPAs7vTm`4r?kPm4zZkv_@2rNM+r3VTHl?FgISL_rxTjJWtNT-+^)>+4m@3s=z@XGe}q zPtyod=v#Q4yznwcATc2lc;%tOFKHMJz9PNwF-Y`2dckGA@FU%N;Z?7t3sip965aOq zfN~Xjjefgy+nH+*v2Odxpk8>@Yqf5hMtq2PyrWxQ&j`=e&AxcH7|$OL!ShMR^M!)v zzXp^(hat|f{u=4P^GU70e&wIQU)e=spy^SWdBzyXw$7LFhn?Q+x4#6Lh3cH4ntlUF0_<&iZN+HSzl%_O?sL_ zI&w(0A>}Fg6e(e}0}t~#TzhoOOz9SckWfO)fvn^RQm-y7Owi>njH{^=m^W4Wol&21 zhjm=RS5uzT?8p)0&N#2%%0^{zDKZkai1!u)VN9l3Gk$93JJ{ANEA|drSk#GCx`3Th zK5+jVu59H_A^jZIeX~iIjN(X1x`5OW!(vAHc45+^DAq$b{*b&T1Q~bF$W2bwHW`G- zV24`)?1>w+k;#LrPPLmshT2wn$RVgw!iR|L9xo*uB&?SS7@%I=P&!Zv5LAc@5{5w` zz6tFxx(kci=(Kc_kyW>ahxOGQK>FM{FrjTxGvpJ-CQg_-8CKbOtRhWdJ+N0RP|^#Z z?XMTwtQX$ctru?M2$#1^eegA+7Y1v6^};;sg=|nS+#J+;;rzQJ5js25;2d5`v!hX~ zY4CPmmI!p)8{#f%24{;-910ucV9A5o#zf#bvyeF7?wxz|#0W4bR=r9Drce6p0TGY? zI|~LJN~}o@j}hkv>m{cM#Ll+{|8WBAsRHU}GX2Si( zw0;Vf3b@a-zp85vbPPJJTXn$MD!immDv8{&_z;1=JLKv-c2P}=w@$( z%XhGdva5|X+d`!j>k(XygKI%K4X#4YRZm;0j$&^Txe&pUzP1!2-&<^|^)}2q@x7bs z+h58ECn<2kX1ev>?R9*O5V^5OXx)XF%)SDoP6zYxCzwc2sQ0 zE|7wwU(Q%ZD*RZrQ`24{Nr>!R5(YaZ3wYf{oiNGc&n{zHRCV{0^g^n?L_f_EJrk7Z zr4MU~{vF3)=|c#rn_tXAZ>1DnIr9=~B51lz&zBUMSksq_R?S8C` z0+7&Gr|7>HjRC}Dpta2JKuo{XxCId7m%)B_&>>JGh z?5=tiM9p8am{8S-gum3iR=h2XEpY*wUu6ZZxp;P?jcnuY!gqS?oca545Iy zme5v3sJYzvaVa~kLbT+Xnvm|vG zI*US=a4{*>C`@B?Y?dbFtYTe%*-iW0V6rRaEi^(umS zAx4-K@RFDr3|`7ooB)zUAAv-FBm7JB+vQ`ra}8Nph@Y$mCHnfT_Axow;R3W2y1}Nz zXyE{p!k&wX{elCwib&EoRKRglD-dQA{dLU(>zb5-8J&;p9mD$KPyb`uWuF~)GSBkt zy77rj=Bu&Ep7zJ>`ED2-{oB~t=bR+$<#n1jvm*)f+l1N`E&)TfGL&OYn2n!^6{0}# zWe?c|0^^m^O#tJ+qw4RN`a7=vPN=_=>hF~LJFWg^Gx~#uNcc$;8fI1l&1$IGi9Kx? zE4x@+zY{1@Me7W_ay&=U_u{y>DZod!U!cLgw{jfL+VYbdSl(ps33y| zA@#B&s^TR1l|mcrWM>5r9HN+(g7y0;UYi71J+q&}wdkw1ekkmYrv@G)8kz#u6Mc>JCr#>~K~y>{M@DG*PCyaKXeurdzqPLqgP;4d{k?KDMW$^KA5tbm8iQ z=#nW4#8eOjuEptK03Sq`cu^oAU;=1Nc6HW=kqs8@(^?16Zm#lyc93DTPx}zva)G$0 z>TWLbp-u*i!qn(VnGPa$^NbG_ycfU##~1bl3nmPf?IM@Y3LQneko8M;61Iz4e$mlj z``JG2cM!H)Li1~M;My?;V|{R)4npk~?>+*ZV*n$vV+@S4orLX!EhIu8}@X(FOFvKkL>Dlf29RZxKHxC~xks7jP^#c8(+ry%0FrJo1NM z!}Y>sZe${G)b-@_SW&GPMkkP%Hg)%BU5{on<0H@4f`Qxz6cj~DeR|#AvXMhrX|(9< zYs3r&kp8p&ini0-wNBHi`qpB#y$WYYjKaSb=g3y5rga7qzQ!NjIM-U(vFU&T*TPXj z@Uaxz@FtV{6=iMgr&8Aht=}TpDQq>zzJF+k&2*8PflnR{pT>1w;);nC#<_mzpo3GAOLEpLovLMBy0FZs zom;%9U%M%W*b_Acg|AKKl2@HuZ6q^eZLDatl}(ML5DRYNlrQ8IQz3LER#wNc#!kfd zw&3SRhD#wz_(t=Ua_mG3eWCNA3I#ff7Ibt<@jd_PUY!o2YVGEZp{NR#rZ(M*6W`D8 zYtT5947o!wH@?RZ%e52}GR2SMdpIEs@ACV8d3wTyx8bv|ZKCW`W%3<$)}_la;^0M{I@w$=)TLS}GK0XkNQ zQc8G~yLaqFs^VV7S!la>p8|at`7>88@o{radV%Ay+D@BJBX+S--=PZtqw)L+f7mb@ zG1N`eQ^mN@HHdS5Kb~(otu{j0gj0T>+W-S#?G2W%t>&%UPP1;IFEk4%9*mKutKW3@ zqQe+lh3BbgG#9mE0Tkmzy+9Mjmz0BxyG?9~$3P3Wu!hN3b>{RaFvSu9auXf7XrWNX zBy{3?0yw`2*$H#Gl7c4LimSUrjH|-ejVIHpm>)AQH{Gh!p484)~>hR zQ`t-oxN8~%X7Loniye!KuA)(e;6-ChBrS?8W-T1T80h8jFctKlsbT1tz1{Ck zIC>N_5cYzOc>K?VBBcpZ@Ol>CQ+;G!!@wz_EC_SATlH1kY5^K}$cun5Fqa2~LNxQPRr#*9?M zO>;JSkHbx3YY0>(z3_?tdf_tbg@4_x7lwJg@OoUJLs0%Bp#0B=BmCPL`8fR6YZpi_ z{P-n9FZkC~VVC`p_k0c43td;^WXGIm8D1D29echO3uJqx)e*k5JUDq|9>>rYv3HK5 zs(hFiEPm{*RCX){PDyHF!~Lp5#h2?AvKx_TSku;!RmL470)TfiQ?{V?=u?IQS<`TK zu+fgoIB?K-sz%|jS_|-CUE?4iT=bgoP6JfYU$w2Z|8aokCJ@;QtoLpl=R6+@WYN(& ze8w+Dmi4w9oQ*obQ7(lFnpfK^=o5r6(pm7y*pS8FRN^_oF}p~xh+Y3vU#5S6PXd3( zrpNSrQQbcb&i~T4Z!F$FGxuk26{bI0@0*hMFdIX0gXs}en|!%;o<8tnaGr|4jv@r6 zn`yes!2pMl+b)Ot_SAFVKOj!^Q0Ja1+vVI-&wam?zzFs3sj^+(J@wr1?g@}k_nt27 z^;^nzIgI>%`)(*H8tULvU^{6M>fuvmebTEw_o2P-UXrq*K0XDvla`@QK1~MS$*1Yi z>0$B-VR-pe;V!Dd6{I0|5ID>mrHXbDILvvb%KDBgK_S%Br^l!?bV&&b0*^?&P|+YIq(B#ElVhCFQ2;`P z02fdl3Z3~}U|gZ@O?T1@FNH+!6IA<8WDLFTTRgqs1=VKwD7rsi6}>RoUoSkudLb6n z3o{?kdf^8@f}^W-+JNfrq#zqAZ@4#VAVP%<7XVlD2#3cHI5MAACAx@CUT7{M1;RL- z-|ImM6C7M%Q~-oZ3of7rB~(OkfeC>SDi^qbqEx6b-~!VEAyfiz0ZpmUX)h%dr6zh( z0yCYd9Xi1UhGNjrSuG_LF?vj8el9p#)T-bnVCMkt|a&|@B`Ouj`wX3D^qZd-!amVo;a*~eJ7^FV(aPbMYp?Ws zzk<9=c5c4><*++yc99EE}YkdG3L&t&f0!Jk=;L`uh8lzUvYQmJ7(BMxO|P_k=}(kaZoP!GNlR}~NPSw2$=Q2-7C=s={3^WxSL z4(M{g5`iQVM#KVxgANWSp!*n7awb)Luhrb$^BxLl?>f{NVik096=ni1C?fy6y9r(4 zG~;{w20{TBwVK0jirAUMniO~9FR6BI1z}#66_lB^bs0q#a5_s1@Ih#>oXgL>YE&qG zchx9#$RP%RpwDx>uY#`lL*hFHyE%j@P5AHKJ9n<%NNCnXxS9hn3ePx3gVOU60Hc^m zS6$50YLzA`zfn}+N#!Ca#Gwg(g}Q!JyieSV6z-4r)eG;xLVDro&wF~oi&kcMA=dt0 z(F-5zuNN+}UU)F57cw8vdf|qPGan?nL~{pWI6dPq-BK7coIw`b+fVp<0NpLyxX+s- zQdH;89ez*e*^o>=C2>amHHN@rioU4lEVkphJy2OwlQO|6prgoHL^!)e`)D}Om(p)> zt3j=G=MIon!dD`UH2n(PtoLJY6Rf=D1y)xMyNn4}ky>?zLx-nF-!EAR&)gQ0o_qoC#r zT17_1fr3n;oStO6T%Si4iNw_*=+0JlVk(?09T6r#Tpm&g+IoR6N75Iw?0D1106Khn7VEKZ)5n^4hIe9A8<+ITa$84deMZ50t&y=1r6Qc^G$PvY!XVs@kUg&H;i7qapw&~KSq zUK`i5H#!IrC_PIv*t6S0D2!PqSbJuUG!TG-*gvOUa9}^=eO@P15c~OCBBJ_4sb~U{ zC6`ICHzBhhPf`3T7Wa~FNH6@`{(51N^}@gE)(aE75G$$m!e0PNpEJR)kY0H5p`c!v z7-7ADg;@Dh$YLSGJ5~{maN85tezw8h?E=%`RAoke@JT!zt0ehlTy5R22bB5+K-ZZTH<0i}Vo8~7(L^?$q69Hm9RcC&S5P8a&(dA3wCr%b4iXt}#ie<`IPg~}kV4oPew?>cFPOZ_SH69FlH;cSNdN7NGAzurr%^6f+INI2W zCImcJiU9J8MT}N!^~mUnocR`>nLpJdDNSQrRU9EtqNsyBFTd5tx>{w{QH}EF z9Jk3IJDPlqSXH&i@687Jfocy!L6}q^C6Fh8L`|LuIJvL{^Weflp(AT|aL`1sFfwI6 zIA17?g5i!ykve5iw;aj)QvlDN4FIg)uHgDw6U1WxF=jph%D`FMB*o%q(E zUYJQ~of!WTbRs2`6AdQg@lGlbp8uuUSMyX@^9&d*oSgrK!NWiE@elqc-5UPK_k9g> zgu3<=jFv{npXHu{?D)jQ^z)S_bl{$XvvB0?&f^g9q)wfejRl-mzrGbyYHWso)c19xC8u^&%d zLK$-}$Kas<9nl@S)^`Td^qAUtaqZH@^Pn;f9$Z(6%l_sG*biz&lHW>!59u0^0(~NV zAwIBkgM;T%HqNFZ18*}$>U}pB-%ngIp+Ji<_AneUcC`h96RRg~B^)R;uL;#fS-mF=97qOqZwhE*vQqIymy8R_UOI2|S{_YjkT>{U7~5Z-@s z{;xO|^$5H^v(mKEvy1SW^0|VT2&=GbWycNgHTzpg^xm51{0M2D_22b0&&kLlN%Q$% z80I|%7lze}#O-rH2KB=56Ra1o8hb-25}8RiW)Yql7&r@R?%(}t)>%|>-{;bwte~VQk%_X}~zkcgRqL^4sY$Q%6 z78Bd~%itErXJyQy723R`N6q&ts_?~1%+~qbx(qvUyd3lBDJK_ND4u7lzqUlzDk!F- z#p||b#VWqbV`af{DAgniMC&UgZ=-PoRVT3>&u@T_nLlBr*hm>IIhXBC=M*C#>j-`u zjpuAB2XiLM8?yY;n1Ce6Dywn%Q{dX(h77XzWUU;HD?f$64=urcr*3VaThS=I{S2D^ zGA3t{2Rm17#R+k0Q`xrAd04d+@o)`knLRs0FS#%D0bSAF@ARuRJZ}>z@DbOUYO72CWa_V7333YASB`JTq(y0 zP0%facYORE_DI?5_6`pie2Zvw6@5|f;(IpQrxTm7UJSyB=T~JEWxLF57r=e#cwv>q z7id{1;sXy*VS}iFRVbW?ZO#rYZ03hgr)X#J_aD}0P6jC6djzoZlzcebR2 zEVqY4o@{K=0H;7(V229}VT!*I)^Jc=sa=s5r=fN?Jn<~APK#)jR|5mGdB90IHG8G% zEVxDZ4CdRdR=wucBbUeNYTXSy2c=Ygu249LF-AV;2qB&sT_?Z&+hZ5M+G;~+)fh&6_>2pE=bY~{^(#3G_h zaMx+Av|NuNcc6`Q@-C?9Bs%|MZX^q4xV8TW7vl0SXOsgZD-#oSg3|0bZ1a!Me= z8IDDW*ZEfniYNq`Y0e0i^^V#M0jEeITB}F%rwcFGxHM* z$+?AzGdSbDSWZq)%ugk8v&s1QC{nuc6P4583(+A63wFm04@K3%|MF0}ho`eMn1c4E zRfBRVL=iKtI8iyynhF-N_@OdsE;KuoUxaeb!-A(xwLp5i>0uylLL3_2 zp|<&eY=U^6+w|cL7qI)8%IKFvU>%0yY_7o4C4w;`0K$4BYObH@>gqb}7Tj`@W$4MZ zd+7Pl@ZvCajoZOrA@^()s{qnevD4ig%lavIFvCJQLH&aAHJAqc(QOxtj_c;n!Dgff zF>e(F(^1MK_Hg8Eu9%>3FPMm{(Ps`w^C}?carRDp53>YE2DDxB!4m%`R1-#_#QDTk z*8Vz)<|?$XG6_#z&7Fg{oMd-5&R=tRQD}bOkm8>1ZjTX z9Q7AOl7r;gL<%_Br7DdF9z*waagLdcj*AO?-mxH6OxyfuO_z zrO&Ekll8)VLA@~X39T3Y2KU=WAB@Illi5?4NfIW7h?muFT;?-ki`oo0ITAm~<<3I- zwXn`e<8*m4A=uZRvq5f-+@6v@Ih&uuXfB3Pp}Z+{=s?p&X?ioYjZ26w zP;5nMJx=T?Nbn*zGz=7VMr4#_P&7}b949tHT9D+ywR2V2J7m`enh3tyb=)Y-X)X+- zSduQI@!_Go4yEUGoIFpm02-K9rCKilQHja;ngN`t!$HJ-iC1*7T%wrwTmqOFWj1a2 zkYN~*QMg&PE1?8e!f8>`v1+1`D8ZQku|QcxDRmbF(wLM^Olkuzufz}YJ;FO|*RH@o z!)~-#JMNi&q<}TcsH~tUqF0D+rOGRokOZHwd|HX=BS^f;(G6#pa#o~3cNa=x^e@(3 zKGx(IMgbu#x@{Rtx3XBSLMNCX9>wDMYN4KQ6mI291ztRX0=|VF-)nQly{LaYC=5Z| zBN)wj1y9p=*di+A=)brkX=4dQyAhnn^KL``6!IsqGZIN*SRPR>gAPoY1kj@kErh{4 z*6tX+_}(RWqhe7xn*!IWw_?843e#I1T7e@eRGOOanDbHuIDR3iY<@y8kx;QGEC&v^ z`!7At#Vfe6Os)tq@$IQ?jTfk}4^SdWk|%0mDOAic{L`gQRadH*WJjs&wBAgsSoixfq~sZ zP4WuPi^Ae{G^Vn*DmjD6s$}zUVK-o4ky!RH3T?MHn(DF!4@Gk!geFZpPA0ADd6fA$ z;hQ`)t$mZ48e^GwdW1}ylS!nScpWKgs5)=|KvJr?-$6_Dw2PQ#OE5-jp1ADR?$F?| z1y;qkfgm*U95gbiBCvs7DAQGmtTFMmS=giGDY8Wyl0ap{Pg-szgtTSdd#$B>J-QF$ zttqby1x1^|!KNC^0!(&2uK9H=s!I;m-zBWh$>?aObOA}v|0+d z9kr>e$&lPNCz7akxM48}>@%OI^SKZXgC#VNQLDit+j5ZZM)9cZeqygg*KNU_36zA0 zOATCxm_UpL`T`H-!)fj-&Z}`6xn-O{BKZlq)qSi?;$p3p1HD)J6SUzhDs?}K^giMB zQfpKs1`6w3s6j~K;2yda5i7E0;g#q|*oZ*}l(h(gEdv`$Y@~Qae?pgg_nq{@>-+14 zDb@?0>edVMoTqS~iWdD8p!CU8Xt3UMgL+{;rS;xt=)~I2ad2q_F4SlY2+zOni|2jY zgy#o;$ip+K{dwzeBY)mIKPUQYrrmelc8m4b;SM|>*81yj{yX+08T}q0#%fKsVqlFu zJt;)va7Y*atWxBRtoI9-7av{5@+a)w^1`*{xvL9vJzg&@TwFN4jLF;=`RgWXlUU7Q ziwTx8v_U0$gZv*#RFKsH+T!FvTu{%1gWN)*Po+3GSXH68+3cM=4Pc##-`1?gjdIJ{}k_mKeqi1ha#lMto;*a6yyoRbVc?(lp~n)V6Rl zQGFvy!C~#&W)AeLnUSc$!S+Gb{58G6_g3_QHsmQaB9}~GsV%V!gqE(_Cm{8GKR^IS zOdo7LBEuL$K%#d#{z!oe`5atiNl;Sxk#%pA{B&qIMp-3ipjG2EoU~yt1}97uc|4dr zqWEatWv$U741Q>QL?u7#gHH53HH1?$>)ZZ)A;sN7l#JSFbSMX_eRxQDHFyy>G)#Ko zEF^lLEP`p)U%&3@1<#*%?lW{h`QIRqfuNN8>xCxkg+oETaPBi&FPy;9Lxxw1x~-hr zU>(Fz#UU;vr2vm-)~=Hk?`iN5ud@s;^B_D)%HUA0Bu?wM;ful;`m=WyyOQie^?GAC zdxION*UATLlMwUs5lE2fAT^dMeqK->!DBe(ZBF5BQ0gy3Ogp*fLZiG)cB&wslG<3-Rmc)I%Ht~)#vhc#zq%ON=Vm$j zP6g>NO41)yR1RSk@3v=e1t}aadUlvSgPkI$@SC%hd@9o52ef}tb=I>CefzhlyS01L z4qCeViAQ~cY7f+PUkb3b36E|`1)~Aee<`%;eCs<4MR;69r!ku~1k~>=v0QH$1#avo zu9-NApZ?KU96ovkLssDkB1yi4Lvo$O2EM6fz{wGC9^;E={P(W>*EVv?O#is5>$$37 z%`mWGgsAlj3KNsp%y-#9wxa>5Y_=dz&;+L2D$<8lM`j7RJ9l)u_?o>DH*+Qse3A4J zBT0e+hLnS%@J?%F3APCrlU9+7TJbyQvAHgt+=!=Fhc{^IQ0jaT8vqgH3xph?$OxD~ ztmMEO|tJ_NuKFHe9fQ|P83I#xieTq*s{OkxRhR~UPee?znu|}!U z8^idPy^++gaFR&;B&JcEI)fHyLUuwRiQee17jmo@{`YRZaA}3^{r zMS=d|ks9_1ZOe*QOXdFI!3<+(JkWuMbn#2i;dxgOR-DUl|MCBH3vjUBI&l>cy zyNd9%EoA5ZXr5O*O3$`OH1ww{mlD>izq=dzF?o+RMbE*_Qo-24y@z)(8+nXNv z%g-XoQd({WmX)B6?66WHIB934+HPXxD8)LDgli0;#y}D)5pSfuF_KMrtO)53vn$Gf zDD|U^uqGX`UYEV63{$*RbpVRm*HOPfLDA@q1RW-7K0qw*R-rBdZRz#?1z8sw6eM?@ zHqQ;hC(uXI#H%#Zjc%9N+TG_GeaKvB$x&%j4uI=-j($Zfz! znMs_643QzuZ_J#|Z(yGsahw=U_VtY$pp4F7MK%#0^dI+Cs05S|ub#yKR z%u!+39;jO{$bALiAgu6_aBC~)oq<{quYT|W69663uc$J^FstyBx@g{48Ql|J+@ag-gOlHid>(M1@N@Lb*M>n8&q&^%9f zv@owV&-U*?@3EzEYqqY&|IVFTGnqI|7iL(4MR}>MbHRLm#e_uUvuQ{b1l?7*0yZGKMM6-y3+PxL#_~BBs1zidLJpBO+v z1=B$$APW)Fa71J9QK2*ZA%22Dc&#GgHMYD=W9x3hYusjcv?SZjZYq3|C6lH*c$5hS zkJxLD4s=G2=uu~=z*eCGtL*W7HyJt{@&pHxbw4np#208zsg9f$UJpT{_t6>KtTU=X ziGJ<>&^qHkVi5#SxuoxSj#b|eKrQ@If1R2b>%`)9S|<`(0K^LyIB3+eH%XZ> zYE=?Pa+)@!Fk^7?*$QI%r|cZ%dInj9E~oP8Bmy3`rk~ivNi%vE4~4jOf`j-fW1BE+ z!ZI*FI z7#KLChig52aFrdaksOLA7Pug8E-?35a$JTA*>J)qYT>Xrx5$8WTS4NzP^JRRckl?U zz)=t3jap!fN3v3^hZN<Knu>x^C28S6ob{^~8QGnRhgH&AmAiIk&KErPtlGy4LS@({;;8Vo0sK*7@b-#dJ26 zJvwk6N5|zXY<`9-ZuRKEquAt=oLhy8%UPG?IE(anDr3d2WwUt;_l>o8tjfgHMBZv{ z67|P@*>iL+Sr1avz%J; z(WQh_Bfmvz+$*q9E7nOw=d9J+l}3WDFQFU!jt*RPXls7cyRcB9ojy8%U}y~+Pbp`{ z+Hjmk5(kQIp~lex8rS~~v^)(u(r*_n$49?Jw0!LgJz9E4w$DGa__Eqp#{WYXEjb&o zURE>R{W>J+i+>R830E}zcDbTs*S040pKsszbnTf09n|r_@1h$2(C{?- z!}=bE^;!cK?ns$`=Hs`2|HlZ{V@7{6w6tuW zbX)=cwdrQegtgvwTet(&x*pX{XOXL+Kab$E(<(-92)Y)IJ0Sr{8@M~L^YN5V>9m2Y zoY#cQPN{1+QiQ<(k7~V!l-gB7S+}Sg!fmg}@wrJGCi=EVRH0o3IJgyL5zC&BXJOl% z+7d{}HqvClwzk;VRAa}&5m|Kb2>OI`p2xn}() zT~5`v9}L(ZUW|x8pr~ujFPyz{b%7o>2o4Y%;$Rt?90?1j31jm{i*6((DoVDHrXdBSZ+Zya)Op5Mv?6ET zMAfJT+ooC;w+p{FPU)`E<+dw0OIvD1an=o-{lyJBL5F`jnsG{0R>PJe{BOTz8gPuE zQEU(9$~al4S$0Z2T41dXbnMNJRzh2-k#_jw{u2HBSfYO=DAC{ht6HM};h#hz$h;$Z zz(MLltogV?dbr4q0lq-12g0-`eU~XnpDJ`N5cctaDB%dJrlc&cB1Tt@de%d39oL%T z8a3=ZYpq3lv`O1CsV30FF)Q^A;t=dLN%U_MwWPt0Y8IaeluFUDMEs)`zz5FIU=KaM zR@Ir$V4GE3Y}(%iUAD0q+tFfy3hDN6hD;MAJWz!8XwQY)y|_lV0ylRxNSK%y%(a^& z2Pw$c3p#=HWu?~z@lBAZbRF1mCESun2Mkje&=TelVqWNg>Wprb{Jb|sw&vsnKY2sp zMIx;H3s+t}4lSsngE(3WSF@T0SV5|{o)*N;!i`61*gcIY8dXM&wWb6Dh!+Y_l?o)i zCzaZSI@oF8O*$4Uw;Fe7%=sT&T>E(X@pSC*?cv-Wc4_WEzJ2nc_^H_AOT+P4?s_IU zePfuurthH8^~bl5AIqgq4HpI(kc#@nn@Z>d{ira=2>?*Q{i6Gb z^-C!xBMge?fsWT7e+X``>vPHPvXi$#rsPc!>Z?l$o~Y?`3$g*+h`kV-X(rA?&m(ot zW6%2YKph-o^XfZR{QBd^?~zC((Vv1u@0}!hf|s^WRK4ZcP-Ky$`TU1|>cZmv@A=&Q zKO+m|`%m<>^uM3=!k2@3;ioQWy>RI$U+59LchXoN z#&+REb`Ze`xPPnFLAqhHfQ?}(Z2CBlB0T;vY&Zjm{pIF&}!aGXlrQ%xycQ zcAnL!Kex%AejHJBX+8e<3MNm&8Vb0i)JvKF?0b4XI=s-R6u(BjblGc7E%=-8;j&>G=1G&^{FXJlgH|7Y)A0OLBUyYWp( z(#TC9U;aD-h4gx@cvsf$>fyI!*^zA7QesO+l4CoLZC27sT6?{#XeG-}2s8%RAhrjlXsCL|#^ zmHgiBl(!Yy4{kh5gdD`0oFYI;l&dZ_l-%M=t_{&t3ZZSa~rgvx-Us0(TeU}7=<5q9lyg}%yL2J`CSdGqR6M4vT6`uIBQcp<2E6d9cL zhLNq@((2TXr9C*r;?xQ88Ee*xFIl<>%?9npWdIza0&YUD5*P+N+JcxS9{Z&YK$o7Q zg;q2WZX*Wk%mnxOb5>naUN?ru%R7m5byd2_hUV_%k`?7GrNJ2(;IbTnc9P2bu>xrV zt8@gwO8a5y!Ytq^LlxyqO;Y3R#+J`jU}SMk6_mbX)J=+QF|Px(Qy3AN4!kIE)pWXm zSQj98zhIkwY?CONs!x*`u|U8hoi*$$;{v2H+SHVu#MK2yYi((YI{FPxj!}p}it?PF z@IXTWWoSGvtb zLdfK1uy33~5cd{mKxHe}=^^LQj4T-Bkt1G=sw1M+ID@2#C?50r2PAPjrY_(uy>|ifB+QIr?+K(Q72pxSAaO z_PQ`fe_vWSI>NTLyebk=aArMJ&_*GgVE4owFKb}d{V-_^OtT(G>N7ce04j#J-F$_} z49>kL13*ZOz3#f8=Kkcy3(@Oq_m=NZ-uJiMpPW8l_b0akN{ygQFBNI_qmr@zt(9h9 zz^Mi)mb3s1#uQ~1L-m?)eL56*AyFpa25YUM47Pz#xBh}51hJJ?f*>yxLSRp=1i@N; z6sLYa%wvUMzKCJTz#uu=r3cH1`iEfQ+PzN$7q5-Z6-=S$EM#jP?9vkG$Af;Kc;_^J`J1dZoZIlClw)uiHE(F4Z7OH+}v{+=$ zF%Misx*94EV->^eX%%Ns*+drUC&I%L!>8Dp$$He-JdB8(h?}m~W;L&hq1zmfx>&Kp z^iA6`|AZF}F=-A%%d!h8+O*B(Kq#&kmYQW6ywswmtST*9Gx(Rta9RUll^DHgnK~H4 z2P->brmP3?U9_grtQIy8U6yjcw_ULCvNe}Ar8;0Y`fd6LA%9Z6+ZCs=FEiS3geP6v z^uEW5o6P7*HVx|{_Bp@Rcu~Jvqld$!#Ce)?dd<;EImj?9Gv8$`Soo9+Z?4VJUnU&= zhhdKX;hmPFUxF}u!ke%tq4e0prIL=(m>ljIdqBazn>-VBg&cziSkdx?ZyBY|Y9}Rd zLr@?C^LqixvBFlcJuaBv6oqabG}Y)uVX7^AM$4^71+Bc_&=3)FC9_-Z6jEKa{V#tJ z8b{gd3ZpR?MAQ@P`T#d=AYbz3dUl2h5rM9Noa!)vUM?-0m*fSX6=Ob8J}?XiaW zNE<#r`W8TZ4$Qpzg(lEAvs_?f?$CR9g;L`HD{{`Yyb40tv;G9&7r{16iJt#DdYC?h zeGJ>TY|fj_c#0$>W$~w558-%~3;~A5#bhQ7tSH_Qz9)MiBe zG5)}@RkE911 zW2Yim9)3%Gp-$bl?d6mUx2_M%g-`sz?s9g$5t@E@Vq|E3aO+qut9cE$XR%S@V#?qo zEnXQfDz9G{MQ-x4+Pq(Q0+qE`S#5zCTKb_AJFDsi`wFAc%2{h%9*5U@ppg5~NU1Sr zMiJT0J~3LVHQHhK&60;h~2ta5ZPaBxCd zXGdW>6O}DPL%VmB7BQG=7hyS-H4{dW^UXmQ?hKX!Rgy4es20Fbt2YH3+DW^67h;zR zherOEIW@-XZzk=&DqBvw$DY0UygUDCS4-g3h;&AuOjsyp z!fW@~vw!gGFNwe4Egy7!4?lBl%^m+WgmvTh9azb(_wTu$f&S@xxcLt7fy49af?%|5 z-h$ClXyD+m3z$?D#+W4YR%P-tC`c|i22Z`@tX%GZ6K^4h!hGz42*TG)SA^6iDG&`j zx8huFOQc+Maq;5CwE@>@$ps^=2pPXb%3?rjjFK}F4BCb%45A~;sGUNlg68cap8P5{ zH*EX7I$nus#$WL=Z(A~X0H0M`k;kelwY9d&3sH}7J4L=wLLj5XC~(}CT!|lfYJ&Tk zFupp>P@mWlg|l+y1!&B+pg^6bYxP!c%d^{VCzi4UocU0D;tLbtz?m=Ff>Ws`(X@+A zT1gA0kWH%rhha(VbfK~!_AI?-%%2Kva7+&11xuGMl~TNTI?Y?{iIPsSf~5vqcmcz1 zj*d*>7EqDzg;K@0u|=>i)C=~B<4X=->DFX^ZS!!wjRiCiXwn4u^jb6fw7a>&cmY6J z#K$X6_4EKntCAADq#)6OB$)PS00=dp2|N^;o_V=q_Q?|^&>(*Q|oPh0GW;pv{tAh@`xU4od!EXLaA`H2pbeFNll zE}i5#m+2XF4D7)%PW{h?43xGsPfp8=rITjX;A4o$km($K?#JPO57cWNiMHD233l}f z8Wbuby24{vqASJ@-%PnKPSyg=P902&n$F54dV-q4f8m8KJ~*_d{*_t`LC`i7hWlH;o-1c zm^|Ogg|3y62u9=Zk}&2-ZYAgl&}Nq`@Bu6$z!tK%Aom}3{}w?;dZ_SF4m1jp7qUb~EnyHf-6id?+ceEjA1Q}3&qU1VVpUmS#?6?{L4#)5qU$h0K;PER*sd>z zH#xhi|0thhIjQB2kp=0)V2Wx}N&qZohY%1NT5#)w->4wmvQg$XpYZz4Cl=#YCn+%< zlRR8NfP50H8MX+0+hgq`qN-$p@PkPhQ}z`k?~~-=CM=zZHu62PBN8Mhu0ly)>I6b3 zD49?1&yLG|2^oh8z}yz_d8}pR^V(-s51kvG_c|*ATSJXIAkzeDv1TXUB@v^K7Kho#$s2F=2hd-nXyaOpC^Ma9b+;8;0ZQVxLA>HI;osO z8AX7{atH>r0~4Jw$OOKO+GjDB#!U-<8Y;|fi2E!SGIM2ys43E$08l#NNm9#XZH|s} zOKAGv3v=|DcUX>|J`Vwg9iX0EoWxKpsbUhapLCc*n`*2weHFR01CGE_X1hR?yL$w~ zR{FFiICwKFv6_fGFpil1+u4R34F!2s4#F zq)C53jw;DH@=Lh9%Aa%MQV=RK#*SWr&mdX287yuV1z&Ky#>OlRj5u6x63z#OX~Yse zz+(1Y3-%n!?BtWtYAT@5!gY9!i&8rg;Z_2zJn3^F8JlI}j^1vxeK17x2_taog9+jW zW_Z&e1KLeCAX^6Ierb5ey8~Q?0g^+u;6qS?R%)k|zLqkA@>=|g(>Feq9Zk~q=>n0F zi4uygSHM@e;v^_805h@Jfn>RjrPHQG-db#&(<9T~div-gr7`!R2(SQuKE#Rk5TGQJ z3rQgvF_)zhO}Kb2jf-7uuXLD}Dp(sc%3ncQxVoHff{qfUz2M?t#I3Rynhd7wF(Mfw zO=Q{QkqO+;tpuMM4fjz#_410CMN&y0eIUF_*N&QE-O|WLjyrLRgc?#yXW0wM!wot;+H)YeeLD zP}go@QO=cz#(IZx3+M*t?{sZ3y%wrkihWjQ__IbBG0CA+!0)Xo5f3dMEk}~Swv*T* z!Y?q1Exg?&qDBa{VpNldYP~Vr1U@myRejcL5l+JA9K33e_FsKz>6ar zy%uE?Y<+?=8Z_z`gL5p}%;MGc2J{>->GnNhZ3$wV{ z?c2eg&~Aw7Ew!}7CS}xguO)c%+qP;(Z}^vCUR3oKq|<3#|30z9lIHQZS^w%=ck%kv z8d^kEx@cR5Z|b<13$VV%n)zS52koLC$^-0bvvA2MQoG=6n6*fb-T{tYBly*IB5MZ2 z9R0=5w6f+Mw=$3}Zt4nEQdp*^lH(M^unWYe3v8jYw#-0)c*u-@DQThA%8V7qus=!I z5qZrQ;B#hWX5~nRr(74{ybEJozkYFQS!2oQv|q+H;`d4Wm=HrRt%K&1QbfWNgkukn z=xb=o;ISd}oXsXoA8@wE_Sa5egPKVUrpMA#*(EhQQjVkW=*kDDz+0Ld4g964mdY&@ z$RskkD+AqEd>l}FyQ_dZ`3`Pfyw=XECQNDrBP@(F7x1=T?i+@f z8%R{VOFS5uoUP)5t^D_%e;xWmD3S36Bu*SSc!&*kCF$+C)dQr?cDJ zy)3zso!|m=ICCkpuDlROnn&hbh_#lG&LE*E@sHut81^(z2Jy4iO2n^yc;blPjtY$!*;%8H3#IHy{5#oowL5{w@w#>L*WXAKu9R2D~TAA^& z!w4Erg~(Ul9g&2Uz!pANTV~uKGUGcXEj(mp#`@DE5lx;7QMi8X`o*0~WbIl_%q~>1 zrMJ1VI+KCHHryS8SiioryVawCA{HEL(o$1wvM^JV`SDl-ca8Q;(=m1sVn~$pfg|wM z^vH)sUtMg~cdH>&3&v5TsKzX3bO~!s(4DgTLiMkuWfe>VL5pN+b`VL#2cc1wfI|BE z`t@tqu3Y(BU;wQ^PNpVcwapg2$%ErKft)V3h$t%DdQ*0$QpX)Rsh8_?kC&{6q6|{tMGTnl>Z=wY) zy(n48Q7-GtUe|aU;5gN)$<9HBZ`;Go52otWHYRX9g9BDQq6v`VFS@a@Wu_oCe6v## z=Z*yTt-dil?el<&`x?&Vg3)IFhlvi(xk4M5aG{djP3R@DW9_RjCZj9PH#G|@!8z_B zZjlqJP}$rx55yB9X7=TY*k~Jm%!%2E_ zA~@+L#aKd8enf()upKVhG?Sx$wYJQ-QDjDcn4`aP%*u?TxSeGkiiE~X#=;g3URU#E z`zDbY-zsV0C01q}eE~e4N|?p(4kPYZ^hnP+M}mztv_?w4$_Y(kUSN&Kdl<&?FKAzn zih~u|wg5~@m*V4W$G{HT(aOzqmdu1>L7-!QBBCb|n8%XB)50koo~CA-iZ+;F zGYwX1jJ4V;UnV+>z~6&c^be`f6XEu5Ph9`4sxA0-LE+_M8seHc(MG4#wbuB27>T2D zLzf#yYOJC%pbGt-Q)sC!qZC2zkK>UdxL!*kgJ)py37hKlITtzn$Y~Zc63j8n`tD+$=?v2-w!w27{ZL~u5 z*vp9jN_|;ih((U;jSko@GS$A(gJrM9x)#~zmW>O=6TIoaOp$NdDq$t1&y9L!1#TDx zzPXB6FeA}Jt!kq&^%ZJu%o4;=_;_2u)u+o2`1gV$a`cygqn{2xcK(+7vY+zkwwuY( zZ@oRt(XW51l^I)cvYj{9bswWoHlis?;Vy^d#hHC+G5m)}HjneGG_KTfQcTxWAuS;c zE2CjC)WRV#T=q0noJ8dI!5%+Y5Po5MPT_V$MPMZkTnZMdriJVR(7uHM*ilyi;VY~L zhTl03{3wayWwpipEh6Us$svk{t`BXy{=QQ-;F`qo<2NHPhmEp4{jQ3-fU#V5C}X{nQAyJpJyg{ zn@IApWH$5pM!3VpgJOwroB9=J#RwfD#n&>=q{KxzlZKSH3NU~j;YM~Q{AYQvd>QOcX*n@AJBr2_+~crq2%BI7dEvrI z$+U}};r^er)6xtSpya+HGi93B<~{@S)RbRsI6Pipm$bR&L|nU%Y%+EvRBdK)E?$K7 z>1bjf2Y*ze*fDu;CRGukL3n?`eZrr^#7M5l48{$I>k%!3(^48t4lg7N6>^_vbEEKj z$Caij94YS42isITOHI2_iZ`v5#Cci|g~6o@%{0^4+E9Ot*7nj|NgMgkMblV`JQdefK>6CuIvY`Z&29BnWsEQTCEqx%^E zU8q;d9Fx8Vi>if)b7nZ4TBug#mNw)Ua|7A{0jkpD>;f-?7<`biWIZ&9B{j`XO~}elwudILN|56`Uq64$FmI=Zjo`(?sOw z2-w8w5Y*cd1$baTe^y)a+$NIep^_HbtmOIS|6$C3h!+9s^NL2yKIb`TiiJoI{=)(j zdH4%VmRo!26gjhRrJ7&gGV#?8jhrNS^6{f0Wk!Z|0EPT!EYLo{?q*`ZBS&NaT%3Hi zme~zBta@a?TW?csjtnD7)W~ogLtfpii`*xVN%h7x2PzJd2E&jZulJD(r7Q z;*;ncs_Igo#{8f@2`0?|cQg+Bd3H2-5|R~RQIIv`wl0&CvGAl}d8@(H@I@xopHMUR zNZgUnbO5e=&|FFFR;-&lyY=#}p&g(#POLrvO24mr+Ny{dX+A z2;N}=B&`q!;Dg%BKiuOJTKH1M=b5XrGAkf}`AxedQA-p27K_u)ijyuOEtl$#P?HL? zvXZ4|T{FYOl4IppwI$DXkvwlLmpmi)@=DDwyH)aduc;|{ZWqbZ8ju2$S zA#0vx5;9(v$vAUMA+>$x7inY+H+?rf+ zq%CJu+o0G;yH#Xa(A6X5iU3^%)@KjI>jg42Si>-xqT(Q($NW;xQJNl*AXeuHlL1qj(fS>{VTtKzL{T@!6abhT%SIcU#%;f&3!;r2BTA5^`k#?Z&i~v>R!i_uh|xjk zsxT718?xOG%F&O=&n7=nY%FvF%9y`p@iS5fb?nElp$vyXwI@|bfZhcv8GIJ#SUvx@Lw1^Wk*ze zI-^APtleNOTu2_TD{d=y)6!@FRIHU9P8mVwM5XFI6{_pi9H)MdQ8Cd%C*#qZm1e#j zIdT~JkE#0D_bI>gy!8}?fF-_6mh3~KRY#2)zCO+&oJ6%|Y!ESj z?hbJTp{5Yl+O7-TAQP;#pBNb?TS;g>N-#P&2OH9_&p{25ZYS#V_$XZwc`Ai_^NIxX z#XvwxPC;zIY|O6K@*;6+&nc2^c(yIITpdiXe$5$ zEJDl&Q_}F>vO?Uo2(mgXvKU5F)x)uTFqv3yc|Yx>j5?jqV%Mg#VQ`H<*lUm~a^+<) z5&qQKnQ=uIhG?-Vl#dp3Asp*dRb+MQ59X0Td<^mx{7JA@{@5i@;cZz;=RbiZ}At)mrh4 z$6s{dbv}yThwq3Qoj!=avY@&TOir1;A}98g+}NF8pF#kd$->mMmC`T~o0olsu5p9z zyqIJFh>5uS^E$`PrrYRY_t+Q`02VnC5J__aNvdYjxgi9gm~3OlT|9>W{|xkPabfK% zOmCFfLZO$&lGp}|Z6ZyM-d&rczg{@{--kJR;hC1Bf9Qbh0^EZGB&U|6gh5K=XriJO zLowuA-4y{?pF#W|dUhc`&>~L*0(om`i1#+QgA8gpuB+l-J2>Qs@#mE}^q+bzW;~d8<5Hhgrm3OdNDG z$S8aj5xN9n_PtHLL(-cKn>X6mMF!O84Sz|>F*`d8fF?l6NOpGJFDgyO;-w042BuA+ZW6@&eyg~1`So}k32IX4cwo1M34+muj*qPQYP9e zORxq}-X=N}nzEiUeOyJ)gfDsoHrN-Ehhjf^SU8Cz$DrAiJrmi+g2{eEwIXman571-Mj-MR;B5-u1kC)$42ZzWDw!J}i0r4S60= z+)#6eaHq(V2TEFh$jX!U@AD+xRWEC;!QW;sk|#YGb5BK2Vd{{biN}LOn|!{U6Zvem zgnx=%sxpe^QnX269jL!Xc(1Vm;B2!k-hx<3zE!|c!m%bLN{ZA`8N|B$WzLU=sre^Stnp(xf}EcXEG0nU4P!Yl&AAOMCo ztrXz7r_GrFm{m-L0O>BLad2LS->QIh1E^ zU8oN`IPA^q(sE2uTV0&l?V^rZxpYEZ^-2j;pGK*vL>&Px^2)DK8)w`9&~PTZ2SHpI zXA@#o`aj_4HO{~h+!bfwU15%XXw1r!E5C#^bd*pIeY>cq%y=JKsBu<*>4iM2zpMPj zC#1zQqx2^97>t7ckr9ZMRG(I}H<$+|jIbtZcvCOKiA!9Un{iSVV4MUpIT7_{JKJV$|8}>_xzui0>!)rlHOG>?k-m$esl7f^VsuLmsq8$=%ZwE1_9drZx%s% zC`y#g31QHfJELX(w_OKIp9Ynn96ssM~iFL@vs@$!w!w z4A9k)g1tXv4_(6LVOsziWx4qv{Pb^!8X8-CP%gT|3(i3}q<(;Le(_fx6&hlUM}eXq z`{#DR0FDvpvBVDJ7ys)*K({QPvX=|Yp&c4Awr``G%&D9)h45VF5Sg4Ons2yjgg+or zV66f`jy}IOM}LcO^sk0F`V~*L9Q{)GCgd_biZ$Ii;M!X)Eu*$!!l-=#Zx_tiEs3j1 z`#X}LY*jhHDVWiF?T$&DSi7|!;>Rnbled4i=xfEE{c$Kl|4O>}LX)0Fc> zqpNJY5YQ~C!qHl{hR99ia_BAAv2@M{U@Ur7_7Qdkhw(J`4uVt_GWk^A>Hf~~WXP%< z5AJ}}To8~|#Z8w|j#+~~0(>ylO=N!Asx)<|;2zmmGHU&9@Kl4UxXvsm1P`;il20{? zvY^CPTO!1cj9uB#mQ&iUz~E6&m0hYWi33d7n1eY&mlS&N2z}t;j8ES#Ltt5Q^agPB z8hf}M+&7*57JuL5`&(aiJ9l3XUaq^ZzS?r(E|Cjg3Co46Zntvb)yE$T9QsRCj2~7-0s5=1M_m8TkIrE- zqV`s8Uu2JJ{B6+_ynGGrpE%woTr3s54vjcF-mEy$? zx>NuLy9b{ps|pzCEOhFbL&QAMxCzuf_u!#~asrL4Or<+1$_c4u!RDfZ#1@1)C8~G} zGL$-z_Io3!%1A@+U9nNR+H`P+ssh}WX}c^Jpp43`sl)YEPHJW?t~7z>CYv*B{_QsN40B{SfkC=i zI(dLpw|6EpMsYRp_iJT}x#P(KY*275B4QL{zP*AG)eJ8m+t) zvO0V9SqSy&$okfnHA8GpcLArRsc5D7t%aFwYs z%HT+o2O4nw$gZ2Fsn*=w0HTevQrQAA-$Q_=TZbzGB1cb?qvN!dzhxd{AK3Pn5!?tTX^i@H9z>-x7JyZZ|~!@mAoz{|+qz?ByF zlW`9j&fB4@w!;YDpC37hFl+KI-hegIiEG6tSCtx&RGl{u0P{$L24D8siA*N9aN(F< z0geXGQe(q%4OB01rW3em0@|HusL(x9qKB8maRkn1_(GTa_J~!sSOVJK7Ndrl)ceNlTLQE^70c$D4N1>AKjI)vLrN z|1MH4ifeg_IntpJMjO^d_aJMy`mML^FJwpKy4Aus)58VanHbKc^SIr~Ox}u8+;8ZJ z<_l4zRbcYA4&2;CnsIc@`Ho0{T7oXqj#%Et)G@Ub-80Zh59Wh`0o?;ZZKM^&1k)_L;trET% z!1!tqVPZ0RQGs9AA>IiBgTkp_pJ@=d{`{c0c^l~IJ?R5&hmR(Tvtw7D0{YeGIuhz^C^`t|E-h&u^qb??=G5|pd9;?{zuTe< zmM>q<`#{JiAJmesn{8UOsN^m)h1N4Rm$?EX#dreWnVU9a3Y;2oQ^;O6g1ZDleE}QL ztn5Satw5Q@_GS^^@r#Cq8kEpF!T0sN4+eO}=_qfffp`eN2znfkCg#o4M*`kFqw~w! zT%nlhl9W4&4LV=Bx^NTa!Yly3aN(P_#L0--YuBJ6$ z0t@-ISfCk@khS!frv+Zgn079*ndi7Xlb@L^E6(nYmOkx9XAuGskSQ1b3>>|>T!|VzolJy%7fe9 z$*$b|7N;w4jk@`ME4r^ahWMn^!hIhIXmjd>BC56jc$SZ`vaOg$1gFBJ(K%Ssd@O%R z;V(a7y@|5J1Vi#wD|vS02;YDwhP0zVlc26;w$$N@_KJ8Mcf=cbNt`98gMp3mj(B3q zeSnMNiDCBvZi^!vfIsNb9gBCGUE>Lv#~~$YY3LBMg}q*GVv)#;;2tn!mwy%5amlHE zPtsA|RWj(76*!O!alu7tbIY5fhl|!^M++{xAwEGcDpgSp|7dDi+|YoSaz4>{V<1aG z9c-OzrjtH02y9V&x=CGa8jyIBrE<9rMmi`dl`APVJlrw7YGTcBV@bLAL~^)6%N{v` z8`o_U0u(5mS~a_7s;u~Iaw=4O78jMpQ=Lw6q?!^_4cok9fiE(8Mi$pvIK6f{4H~JU3k|nLOH8~ zk_;$tb-iOcaCIHe3NtNjgd)Il^?>|bo)~xLzq$imd)z=o;B=IHlPi+ zN9VnEbF{_G>KJmo;)*OIm3uuyLz|nB&E@QQJ-7smgvV0_-X1)A-WKHlNp@oP@o-b& zP&SuKH!V#yd+}{8E$tq{PR<qNYXiX@v!p z+?dXf&*18F8#1#bw+trWQplo9{Q}*v(`hd7@k3c8MShJw{e)c@#`2E0fjrsa3nXdsy>SAL!I`Z~oeFoZU52v>r=mL=Xr={(-xL(B5E=9O(g`i4zI zXU`kVOhMai^E#p1PGp)|Q%h3Iy!iUeC^BO=oIQ_mbCR2Y93&k;kj8Rg%i5Zkx3w-) zVBJG$OCOf8t#TWHIU?a&-ar zdF1^?WL&-4yk~>d8a`;->nY3*6&ixk^dR#@Vd|jX9hMP!NsMKRDi%Oyi^Z9YH=9ME z^nHl_m4(jDv|}}qWw%2i$n!p`C9N_`j~H$s1&3@!U*y zJkRCIfMw`qoit&;1JGeUL#j+%gl38pY;y3Gxe-Y7a^Xdu$R2E(#2cGf64O$Qp6ixj zqyS-YLA7E&J2{ylr{cwXfyB*`B<*w`%7cAHf;YhTW)8Lq0$Ay2yGJxg-_2Ojb;J=o zfCfk7b~phd+NC(F01@lWc1ebB!dJ-oYB*wD7E$$pLFpvtp+3Vl5Yh>|e&9s@0kqE1 zQK3heG7uWgrRxN=i1@ih!GK^fJ(vsx2KkmLHj(a{m^f(7{tm2-g^Yg7zyuv@7GB;F^%~hv z9SAXCCJAXTKv&*;+h?}gh-Me&DIG4Z&C%a29R0Iljz0fU%h7+j4%zSaNz2aSWED+E}SM3I8pdRp@?8tm_jV-Sg8{b3QnUMWSCL`ZSL913CUTjGVK zv3)I0Vzp+l#h;!jaz-JLl=8GBL2RBX0PUbJL^vSsb?WNsc3Z^9A+4+cOYo(?i?Xps)x0jF0#u&+(VDX-M6lbS`=gPzsfA(?;N~2=0o) z9I-z^7`M-*F;_B)!PF?8i01k7#v;z}C%dfC9rlTUsnr2yEY>dF~%>PnH=Ba#4dM7>7Bu0w&eM{{gPG}b5`XKI_hw6}_g;A0&s zY@@!2_wb&xpcSMb9x)`T16Suor^6WslWOp*>7iHJ!!EoJ`WIU@lUp4VAPx*^m*2@& z<<<^wMS0m(+93$7scgo-Q{(Y=l%Zo*B1Shrn8HS!-Jcz07!uZ#SDXb_KgikUGEEs^ zxPuc6g%H%D=}peSudX-&Ar1o1gkfL>Q|9C|vmQUj1u$-BnHqdX+Jpk(`~Y-cL9{@t zWQgn&l0j7iQ$X>v1S13w$?(e{#+@I>{@eqUMlXi{8g)3Kq6~)P7nLqswD`hsO0tc< z035ygF7Nysxu?2uufNNSM>dn2cij{Fi_PZ@E;)9E?(%L1ly$Jx@warB_mpMZ-b1-? zOJ`Uv#Qs9$0?dY2Zi+-^rGEj%5HDc)qQDVSS7=#T1wT#NDJD}3l4#6vK zgyKokmgFzVV#cUZ2nl%UX}~X`bs>M9PnY~xHC1UeCY^Fu>nLYmnE*tntb*06BsmOM zmYr#?Dt&19Tp1jrrG*Hb^oc#HcHii1?Z(D*_6#1BFLo5<7* z2gU@80AmUM1_F@fec4rF2|Mk*HFwYN600&+PNptPe89%PnBzQjOp2n^;2 z=we8$JuIG{Mm~>8v2u&j&y04kIyJ9sYF>fAO)`pPVGMy=Wph_d&hS($sY6Jmi<1YW zV?%7kY_##IfEa90CQG7p!9vC0UD#lwZzlNH%93#>Y}Bq%;36-mV8^7&=FHSS?833t zWz4b(w180qedrmK-mxj9vxLC_Cwn-4Pf$rq=V4WVje^#IVft>O>nc6dU_g@xSzP!w z6Bh#!ic)Or3L{x8_RRV$kU7FMl(V_LUe63NzDG z5+QBHlOTaYBe@wG)D#en3M?brC5@&=7~)`Px0p=EoH zXk>V18sjfgZxDnh$iACEcsO~_5e$?a9eU7DDT6^M93YJwH^rUwV0NOgFFY_z!5A*t zsWQXS7my!Kn%x6~i4RIPFbFzU;2|p6{-}nb6DnYzhcHqc-tW)I0AA}5|N5b= zodexo@1VDNp#PHIb=~W{Xy+ilBkumz-l3lUEkhnk40QGlZTI@ud!2pTy^DMM)|olz z-nMz58%C@C0k3z{=8e7G>k?jX-`b5^*7f#n@VZdBuYbtf*o(MzfIQUi4WU&7ueTfZ z)@x@rbq}oVK^vW2y&HRnwkN#xy+eHjyuP2i=cm@@=AB@43cu^auYxSiQYY zZ*%9sQ199;8#@QQ&07XG_YZbsIP0_nef@pCed`C%>+Vh6eM2dX0$umIFTodYu%~n5 zM(KLz7NBH6#=EwE^Y($>4Lw6%Pyfbs-FVp5t*|!sc6M#-M%U3O(6x4BXYZzjx2|(j z=LQaW!0QJV27ncRv|D?+r^mYwuup!s{I9 z9VDvP5A>rA&K7ELHu_kvuiF8|>6AhEvyO6{k1ari->Y@qof`oVB+wTsEOeu$yb8uV z5>$PvR1CPALRjvKpj50?qj%Dfz-s(~)-ePQMkg07r3T1ig7zjaHViXo4CIcZxinO> zF)zl206xa1{V%|mZOkv+lw4wkg0j3Z-06?L?h}L4;lUMR4LxU1k9CEP(qch8F-;qLiG=lHwl#>i%J^R5r{J!|thS9xzU;hkD)%Z2xg zTsRh%3w_VBa^cyCh{(z8<>c7mgZ9BhV3P*^!Ls1JqHD@x1j|bBfjLujz^|RhRowTr zSWC5oWS&e2CQSfhC{B~p69Phz27xVsiFeC$OsPw%DS5jQT+6Zt_V@WS@LE%gx#~|) z`2wi)%OuA!)DCJ!d)_K`uEKM4+UYDUKZSe_*~q!*xxQ`pbfpE|Q58yjBrIlvE|6Aq z?lYsi1&kRMKc|X3z0HI>834vHR7;{lPt_Qt>|iZVCq?&RKgm?k2d+n0Bj8ClG9e6* zrX}q~fbDv}a0Ma`b=f6k!H@t^Y5`H;9D8q(nz=f)kyJ9%O)#57kAoYioN2Igk|x&| z39^R{kKBia1PXe`upHzgIa_9czN3LS%1jB`LJBqx43F;x2UN)Xb^-dX@!-(pR84b^_+3dH<1mJGS|_BGtzM{E9dAu_8K|@( z)kTD2nZs0QFkt&-mlP6Q8}*uYMf!n)T_U}Nocwt(49yon(^>8dH)5y=b9C4l1`eo9 zEolQ2=p);h#93b?=Rk(RJwVzZwZgD$Hn^+ahs=<$!!l$zydDF-Z{c9ddNMieBz$SA zt3$zKso;oGXcTErC%pcRvisP=n9@Z(IV~9g=CxETo1QAlor!^M2s1;OB{0HoI3aE0J+sXa7uWZMVG(QkV+%+UwmEF2y7(5qh*iL9;AS82tZHHR6k z9=6q%SU(ks^|W${HTdY}bFN!)v+=LmQ(IzvP$bqTOUC!8l~}Q> zkd9+y!uQOR3~G`~($W_uo=n`Ht1I*8aOfp40nR$nir>XJ{+%9y;!Ea1KBMJS>#dT@ z2k!LPT~5VY5{N|Vum;f=)x)@`aG)_EciJet7>XHq_obmmLX#J{V)P&~64fP`u2{Q4 z9_Fp~nn^iv4=1)A_>8rrU4wKjpF~+zT3hvI?Z!GvJRFqc-v)hasm(tyVh6CqLGSs! zT122z?}ouyK4Y0dmXOa&VpjSA0U*p74KSleFUv<=B=Bs2Fby}SzGno3KR5wuIYV~9jq)CJ*E>#mf6rKDM|++gl_v zv0#r)8(FFP22l!wn0S1Ta>4`$0+39eMquSXXtV-f36SaX1k-|9F=oNYuBGr|3=vLBPC5Lp!~%tNr0D$GN$u(07dP(CZRc_99TpevJtlD8l zIlQ9TC@^XHW+jA7v?E4bg2jeH)r5q{%z%befdhWS{!jJ426@SPj5-bAf+BC7P1HAei6h%2YOoElzW&Bm-ZM~fFJ?;gf@%QmtvO3t+H)H zQkFtt3Oi3OGO$;3|HZFHps>Nym^abFRwfpUh~Sn2qG|$ZQ>-py`eQeq2o0<6z=hNu z0&`P7Hh4&2lkATlUmFqNRBP6`AT@$4PS8P40w&OKL0>$&6z#ySWun{m3`g@^m0=Oc zc_21b*5RZJgERI!(aJG8i{XvE3QL+bx=N^PVtmPohLX#oVJYrxkNn|bsO2cI!$pTw z$KdG#yOk>-;%hJrq_E|=*yBL(>JWmHN!wzb3(_LE=_D|$oims;z^K1)IZ;gl1Cx^& z9E{kvYJ}v}xacHDKU7=O{}0jhpIWZz?|$0mb8hY7$Xlu~7 zShE)*Z)EW0w2p=7F9unmmMuzAU(%C}&*b$=v}j3(1s*@*75|8jk)QC?7eP%scBPYt znv*NNX|KbO7THHcb3mJM&XC2pStS60OoF)Y&EAE?M- zmGv;|#g*k)s77MJ+~+m$zw*Ih(fY=fU>eN0sN@JJ3|#sVY}ZT8&MAl*S^aV5x}8Kr z0Z|0CN*$zeQgc|!1uD3xuqmRDUa`ZNY z%)m7icGKwhvZV6fszPpcNsoq+krbDlgMEFaE>#8w?lImCnM+Mtfd zt8#n>T=_dHIqDV6ZWUu~k2wl}+Xl`ShpDmAHw<$@+W_u+KqJFB0&Pq93;U9_EeUDM z=>@J^fZR-@xQhY=Ln;f)5D$g2Cg_KqcYH?zh9vL|q;Lbu@NsVly$DQQ6^f#Z!URoG zV-X{7vxIJ62c7PQ-A&YXF^*u>8cm)=3tAh;{UlJ7Y>fcCh?^)ln;}VJu%o!bq*||7 zPcWI=3p3sbG&`gF3(3nB3x~QfWB}IXA!`-&;O#<+#HAc;9E>9fn!Ny07FS;o+e0Z9 z_8MHOA=LcLzG0rY7QFF-ZM-kA8NpNQlvtDVnaTLKBqM%ckokRjY-uucIjYYl~R zF~~;&7!8pe2mo*yXs1a*V)6nq8Z!x7Cm>zOXbmQz(L*-Tp~<$#q?p(RIQp7+24cC2 zl*Bkde`-&_`Y>RnI~=W)30VnJzzw#Aa7e`o+i2T-o9<78x#@LGU7))RPJu}{JSY%m$>!z$ zB~KoCjnGaRwz=pbM}{WHeD5ct7pMaq*|g{e7V%VNZgNE0fZd2ex5&R0yVf3a2(rZz%v2c#w<+0I4@E;iygYu ziL%nhG+<0e%@7S;ScL+tRv{jNUz;ix-Vv-g+?WMNG<9Is!B!G}d?k%(BO=tvJaPU+ zN)y8~7d+V?=t|fq9a0Q583+#Saip>r z^S+=7(azY8RlG`EpclTcrhCQDWD9$C`4%?!QC>lxg3*%8W6kQ*YB*_}e-okHxW|X$ zUvXIUn$73z+W5Xp70O5YPK$izbVL%vZ|NdC{R7)RDr(b5oJAJvde^aM|KQhOI*0Dq zpF^&&-{)oK<)O>WnX#4D8+&J?D@%nmWU4Z2cS;tKV@Hk7QievmbWee0JQ#q7apQ5(pu#KkWmQn^E z88|ESQn}bs(?ck%4#rNVgW$lZ3dG5lomL>A{VRcf@x@DUTJX9H~xk0LRtUDM^u2BQW-_$!X)46Oa z2Dp*{Q0CW}OjBo73!-XbMpL}@8n=CDR~uX%Vq(FU3z5ihdsF0u!LXT97t8g;gB>bK zliyK5o;!V-$)QgpDZVu%XFT;A79_7N{*XHOS6OR7jFh~E~U6!LKZb!6V znb#dUUzsU5tlL(Mh~=9QAwi#$7-OMv;x@7eO9$Rb|KnIc`H_jjlzfAql$>MYOp+@O zp`>ui$3r#|nwV2!v4%u9W>Q(&Xq5{o1?EEMdhNcMHti;hkzW0a`iw$1h8fdyVuZ&t z3(CwZi^hd28Vi_`=?R?yS*|Ihc*8LkV(Q5o+3~`3RIYK5Fs)(9N5T%5$}qjdBLdpa zDLpfVe(LIc2hCiz4QAQ+Ob$jYER21iLPe<4HPd}-A0jpEDDE_=RK|LG8*nHdbKb{rIIiDgJL6m#2`Hjvc(CSd+K>z2_|pX; z6hw%yG(+oKY;{_RJ2^4|7wMSx$(S8s?UHW8^<_F9OT`*}tQk~QTl!LqQ*VywV`&3e zaRJ&4Pg>SpmGyES#4?x1v#<;rUIC);O^N=?F&u~$1HT`aQ2-2sPNjx(GgF}wFmwqg zF$K(W^2xA}?}fv)7Lf@G<`2-q{kC3(mYE23VCw_-Z-;-FHOz?+W|10&quk&`8u6Qp zo=i4K0D*#Lv5ZptirEaG1y76@Jm2g>EQVWhi4iS{JZAMW>{BA8hCLz7c z$dqzbVHO*0v0PxYAiK_i$!KI8_;#4}_^P*iIW|0aQX*6A`j-mQ9?=jCuKI9Sd&`Ii ztOEyI@_@mT#lsgOP;&jv@9@3Cl`w@VO&7)yCq@@6nh)WrF@_6mV~*1u$3TVTFiBTf z13CJ)!O^R`W7pq8P5;^nU(=68Hj|roz3YoDn-M(hhsRXYe|rCEkqe>a^S4aXZ{7BB z%7vR&hULN+TSP8kJI(y`xLv^?Ec@bEa+sUxkttZPG){^?w|OMjzH7(>2nSr5CaNR@$B>;hzt6MwTBKVnqC6gDXeX6DVESMkzOF#{PCoES0nZSGUo$_(sF=l650Gn( ztP#u0agQ0X&kga0wj71-5Sshg@?n$}=Y@nAfyD%5crmHpU(*J7Eu; zm2ot|yFKJWjGyAa5$jGNuPIIjF^G~%3XdqDFb5_qvZ&dm#A%+ zRi}r9C)~hSHU&j>bu>%h1Sg~@c1XrriYY6_fp6nR>=q<@Fy0>qdi{*v|EZ}6s!XCf zV-AZbj__M5lLK;dBsoSKTTPE?kyTL4dHxfVu=3elcKTo}5d$JdaYNgY0K}sa5)l5v zwp^7+9vJ!x?*UE_iP(VZ-pA$Lh9?<3D`td|`6`U7!ITfN&5onO5KS0;J4UQkW!R;I zM6f!C{7T=VPtYXEd^1!jEE|SCCd zigV9j*R-5`LiFqpIs7yfQtp9UpB&4{R@(1dmcl7OV#>96&CP9#7q=~K4p~l?EYBpD zq?ZmaU6NV0Vs!aQgn?^mS&A@#L2Ng0tj8M$4l_EQY1*G3P3_AfY&35|GniqXf#4#M zQ}Ew8=kTu=nK&&Hc_su>9KU#kC;A+JA`!eR{W*U8c;t`2)p79HV~?Hk%U}NTDfl}l zp8n^5{^#`j?z^w;jyvv{nwgooy`y8*XU;wM+#jEI+G)Q$@4WLKzWVB`5B&Fk|M#Di z;``tJ?cdJ-{O3RasxN=}%in+Gkwjj@@$}}%@h#nv*rtn>Q`U!t6%-fugecFyZY$yJ6^TucxH6l zanQ^0i9x^`SR!Ru_s%=-JdWT5$Jef1`vCFsv5$T1@W(&?@kj9^Wxn*KFCBl~^_L(2 z?8jesd^Qs~z7ylGY4E_q=ES`kCiMj-UOf5h;J>nP>jIzP|pUZQHiJ^?mPq-=% z>rz}qdrS`<>U;StaUqf_2PpuH)a!}AWl+N51o+}V$g zCC1Hm9jdq4sW2ABSay5{mvI994vQ*`b8mh!31Z>ZLXU(O&rWGki^W<50B^ z3sflWFbE@|0iGSD_9>K+fY@ zi&FxYIgoAwy0jqLpbV`OO=b6UV0P0YS5#p2m2*)6?hnNRgL4XYTMkWR_FD_i$TmFB z?1!~!JhM&o&pN@5d9+;~aX!t6tF+HsIY2Z9V$n)hTOTWxyQP&FgTRg@p4p!$4BNgH zhF$C6ZtlNACjZj+X2ZfArgR7Aq)c(+qeGk=i#R@oDF#Q+2V-y8lkLfo?Q~XL#U%q{u)kFB>@X2Vb1cS_n#nWE zN?gJEb9A%Ed9F$K4 zBk<_Q&1?)y{Cw0SnT$ibIY~+!+19QLYD6hdXr6P3@I45`gb|a*47UM4n8AHQ1oHqy zyMP$*3B}b#0t^D}!xNcT3E~n^q=;Bi`_sr0lSSkx0z!z7nek#}G?L_;bEAMxk)TUS zj1&u|1&gZ(z5*26e)y(jj&AM+Bu6@hTANoGHJRN)qanG(tajmk^-3?;fU_Y>=MG-5Z`sK&J10wFxe902)F8a z|HFjilC=X5!ExBTur_Ga$5|U(S~igf^n>u5?B^Nr5|PGvP!UI9NCq_FH81HTyAp+@ z$)wmow_a(3j9~yt^R0o`QZqOkVJP^~AxV0rIKzc@Tw;lPlQiN^G7JQ58Dt1p$p`T- zo18S({XT>;!}$}IGNKe9nyY!u8horreZq)P%YkGjMvY1=CQC>dA0vCo#c<(vU=w}_ z6gmhYU>^eeW_ha%UUMqT>_u|CcZ++y-MT19c$xj^wZXKtr5#P!_|Pm-7)A-{xYHZS z*%M-Gy5cY-_!RN_on9~3sJbQWp4cd%%@Ys-E;c0euQR)ad@#R)F{0LaAH221XF0QE z6r+HTmP>fLKSObWdl$}6cpQi$UWRl>?TkW~g360pkV^yX{SNYGj>Nk=J1 zWE2oGa~9XW3OFG~*{%68;kFR22fO09=wO(pT7@(LldE3FQG}F4rBvb;QI^ z-3Cr2ke&QgE?m6y7@T_Loga`$C5=*7MTCMIA%e`wAXH?R5m>&oG?E;`QhA;H>j)Ln zk@U<;JnQB-JqwRNW=VuZfY&~vMv8*(7*jRBA&DdIh?oZRcxF2El)RhG)|DAuH{4fq z=ldDaliusBhfv;?@BRB9($2SK@z~>y9=f!p`F9^Y6q3Wpn0#R^cBt4P;~F%kMW4Dm zW9rv%Z)@__4fJnD(6z079s>1k!3^S=@ipVl@&tXq7MKlGQmzn)C;8)p<8P(aIWvgW zQz3PmEfR%~Rg$NfxPb3FmYKUc&LMCck3#hzP8Oyts5U70OJo<$xAw849@~>N&XEE9JP2W-g7+=^X4Q%@v6BMWeFk^A>=tWvq|_egRw`bl*ojCxjhBA$z8BSgQ`<=20__2$vxx0MY?zs2l&_EYuSoRH5IJECiBQ zT7xKO*n4;i6pPr+;^G1?o}^OLV$gD04#Kof^$t>lvA!2LG#i5pKek*ZE>D#%k>ob= z9yb!Sa=X9?Jbc!DpiS=T0#mr$!T=JhYykNjHOADQ$?>Syv>JUhUEBd3cdWi6$`?D~ zdmVhwgda>IDWh9pJUbTMiBZ|?oHkeydT|L)N4(92NrVVVdK=lWv=&Y6=bPjt-z23& zpuf_2(|s(?P@&2l#P|$Z#!Sx77*Ab|4JhVk>6E7qrN*$?mAx?!g=46JL+QLZ?XGiP z0@LMhnKu&vQHyhvk`Ur*hl)v3W_<^mF%Q+3UAn;3p%^P7_YXI}7%`NPosm$xzjrTP1f;I;yrSuuT-qDNwa)U{{eO5~mAA0%_nC{o1Ihp}5cF z@ELQ=3q5HB6y^;lC&C|InyqtD(yd_oft|DOVZb&a$MT~{tLiO)PYdE1myv*nJEV}I zz%0}CF!7E+VL!n3@z^jsgw`9`yB_Tu9%u+N+(sTrg%eJjnSBVJ?>;a*8NFcUu6WE` zbQ5la;2c)FvoSsqM8oYBHkRm??nbrG)q1Bl)J-2PR9FN2F>q)Kf}2(}BB@eB=o8e+ z2(YN|rfFAv$7Qq0%ThZVFO*L^8!t;WH1gTb!>x%WM;q4EHvwmYHT1k3H5fL`c=VY-BBK`N@?@@J;Hq!eX*(v}@dlcR3~N3Xu~y=ymjzGvU* z?|dcKWzWN1AG+&$?tJe-j$T4JT3arBR^-CF!*b!S>#bZ^`^HG*1W|E9<8t+mYLgbM zsuLxzpvDPLT#ep_p@oUeRWRMpWt4}s&@g_bE6|=>tcFkg_J(FN88y~nXbWieMDoWm-1V_u7KvNSp zW@L1Deqq;CVR!F3#Fr1_6j8X4j?jxP!21fX(Jxr>VME$ogvNt|$YrV!NCet8TsjxF zh~#c)cDLUT#F!BGd%#6Bt71Akn(+HnQj!TRQK;H$7_b!xqXSnf#Q0Mj1KQ$89B)=D zi3D;1I2Bhs3n;*Tq$6SWIXto0+^AnYMLhNoavc*iLxI7eJ9AXTR%tkWvXkUYQI#2L zYMOJ7exFlBj(!z5`rR;R^0(BMdD`o@eU2RcCO69-Y&Y*bUpP8#ng11u?EZtB=#q5; z-^a{u#j~$OBKL`}N6JDU5|41)?ZZ)7etNzk5blTJ|A}QwAV${!;iPfQK@W1gDA^5) z!OdJ*0Aqsu*6lLaxY2It

3M3IX~Z0qzuwN{NlwqeqQ)<1(xeL@i2Seo9dqLN?wrpgCHscEzMu*Lc}S#O=K$l zF?cXkXG;QWo#4N`vq0-J^3_NVa0W8LHFgJwU{^N6TSYS&b|YkHJ|`=TP}YQRY@66R zCFN}H9%iYLAM|OEc_&PdZC8zwQzzy>alWVPJ>H^x4+6|hOi66J9urrt&IAOJ>J&B> zj{6seu#GVKAfd5mw|5wbighJ@gD?DHI~2!i=p^s@&)Pce3q+@VL%B}-?i;Do{?$R% zX}|IL(;}trejle|z04gZ%9#5%LI3eCbKVliyQ(@^gM8d$*q~ zdgJ5H+dUw8L6G9tE>E*E!}qQCmSyzb{{`R@2V?v#l_to*elMlT?e29JNRxNpc;6|# zKc)}drp>4(Kb+k=0BalOgui9;a#8)QoR?R1`}5*ou=$(z&6t-@K4#`c9GHtu;4R6_ zL0*i4(qM1LKWUlR)r%TUC-jrau%58F)`L{)PyU=e`~I49cAw1I3TID;U;}^C{)1nC zxs`Kv_2urIZ3V1B%ol&l=B&G?lXI4Rqd#Y^Cne^rh+XD}?jf(q%o*&3f1EC)az`Y( z{TVvkb6I@4_H=z-rfaz~UAW<}=d8CMd-rLau8U7~r|VC?cv>Wbsp4VR?1YUgp&78m+*83Cah8sC=*T(CYhbIs^SOHU4 z%>HrGN+)gEmugPh{W57wok@##-LvR54-_K(oV2H1=}y|+fK^?vopFSd_Rh3FX}%N6 z8$U(CmIdv&Oj0H-H=O(9oR!YmrZ3l=voFe=Epg@y?wfD?)HUb+pq_K~=s&u1_U&Ju zULzvU_Gb{*jk_FJA;so`-M?QKhj2ummSxM9KhBUmOP4Q(s#43le??eD42sHgZl#h# zILd4Ds(bf0EyDI&;_Rp%Z4-ym8&8#gd2LkFaa>oP8J6s%qc|*wn-Ri5?JYKG$>dt2 zjN=M`3CwdL%vcC`fgIW_?I8dzihFSbZZgKr{$8IQ*!O`0t0}TI(KjeQ*oz;P;2a$dxnWk7cw2=O* z(CiboXtwzD$Cf?5eW!o9smI};B+3id<@<4LIw$!WNsnMuXBiz)AB?FiXuDde zB+zINDD61J2b6nx8XJucqR`o3~1v$6nlhLMRg9LjC@F!!+q!m9ClXAB1ucC&+M>Vorkv$0hIm};bA2y zb`kq#c#j$&;qyV*4JktH&BHVqkNHkO3!;*CMchD2f$_Tp7BWChaG@$=F~~#1lMoi< zlEM*?dSEy6V}y`a0cC6q)3mVwKXfo!AOu!K2pi;7o3(mI|gx} zPnfPXiEFg0(rWg53Hz{*`L{ac>LA4$$jaqI#pHC6R@LK`y26}Xo7h(`Y!*fOX3O;B zh}AlLkhcP=&Vajw;2tlx8)&g)=SqLjH6$JGM7(&DeYK9yyRwaWWZB@C5RA6J)P3I2posr0^txmd_t<47%2fjw~)pvO7z z%Th#0Rawab!DT9P^y|UVYq&TJb6<7#9sa&bTpW6T-1VW4-c57x8+WKV_+J2padr4x zX2N{I_GeKp+*acH_R+gVF5p1yzcx5>fn9Wd=-dW6(*PG3TPeA44F6MGDxD`%X-8Np zee_?gROt(=F%;Kg+smJceik=tq9}lWCu|C_v99Yq465)%U=%u z+NrW2PMoZ(>RTL3K-Q%rv)?H*f%&SWWXn|}0{h+ecP)^NkXfj&3?ud%1ZJ4Ggv`d!|E7%{5 zU=YjAD(&baqO=zaBe?P$jD>;dC2?^%1}q%j?a&_J?j;(HGHXjzk8W+5N`FPhGf>?K z4&tyO9H(MK1^|}6gA}}Tj^6iRhHdYwch3+@SudIX2Hq4kam#L3>?Vopgt}RQzzDR$ z;|h<;2ZcFXht2Ugbu2kpH{u-oSYob;{jw;jpkfAmNh*gJQ&mKez<6m6+0W*d=RJ0MWB{^+zh&}d-S%gTJh?y2(T`19dGb0~76Fp_8{+O1 zseQ3!UvFaz=b?q_(W19MM`XtKk``WRWky3fkQt%QV=lHbEl7G8J~rx`582KM(6Lv* zzpXFCIBhO););ON@wwLx=OU@IFmjalvJ1AVDM()S>H2ve*RHYwh zn*-LRyUIqwnX}F%!f@v*DV`BBTj8BS6=VY&y<>LuN+uT*`(Gt6lA(~e5MQ(Mh_D8x zPj3HW%ryb`6}DE3>nf5sdZc5FDGOz=x=PsPvlEtk7C^n(dm0(WEhz59%haG%IJtly zPfy_XM-$jDu0CRO3FnBGX7yIGP)h$+AwL$YN&Z#pVWRp$o>Q|~Mirn8tvV@XC>8-% z4aNRI1-+D`)sTBqh<)ObS^+Ws*3%+C^uSbbG;APolb;fa;V9tZm;nP&92EUjj5aI@ zZbCD=Nr4z}{5YEM{Bk~Sy)F@|I zu~keAa{E3^?LKZ}2SAbX&xzA$xN;sTnq10okQ`j@54Ub?1lD!eM}1JrlrS#;EP#lB zY^5YH;8T8Gb8|RyAvcGwE8iU6cL6ttH~x!m4j%@T>gTO@jS|XP2P#6r(cKXwZYVpt z%a0V(e>}S@J-d7RZ%&U?KP2D&T&{rIz8hWv_g!$`DHlryj3uvwvL!!UP03TvsHGo0 zkFajM#DNt$yIua>C+X~NVkY4&ZUNJn@^Em3n2@b)OBc6+^>5fTboRXNp)}p8Tb3r<9j(?%QzoyyqYqWaRALo^{l7llW~t z^9=m^`P&EnE)sdhuY1>Z4o$rH#|IBiUUuKXhu{6NZ~uC%dGUFdomO}5s?L|3^R&*J zH{J2Fr$7J7p2CeQt{Z*+hUY%A=!fxdExqBJqq7(P*`CI4J^1nq?rXT~`k{f#yKmXL zlYvX;ld4n z{rUFi9qV}Y{a4-ghON)|#V_94^xlDAe6Zd7!oy3qeC!)bUUk9D+m}R+{pqQZb3c^r zJhSd?122B$S8r~4^|$6f{rKBjJNBP<-dV@H@4RQfB1!0+o>o7;Zq|B_W01v$sO-naOHV7U6lFhu@^t(hRA#N{zK}EXPx@9_|Ba> z?^(WV$*R|UaqLsglRx{{|BU?f^FR6Kr{1;ap+{Qpy|>|S{{HX&>9LQ!bL+cbcuVT5 z*AHL!i*Ik*lzh>$Rp+isoVIuS2cxgvbjQqJe)yEL?s((A+phJ_ec7oOUUcUhpMT%g zGYx0xtuOq+*B(xOvGoUUT>H{*z4C^CJtuSb>5=mv z`=^J$zUZUB`FZnMZ#eMZ-xzAi5ARQY=C=Pl{jyIEeEL;8o^$7(r{DgS$?x8L#%0fW$9KN;kyF=i z==%7YRo8sw=M8U3{OQQZ>T~;Ux$MLL`l1~z@A}lz8~T1-cgj~*Kl)F_Z%b>}yy^Ro zF5P*2{qEi0zJKekgPAo~JbTNQ;?pDNjkH9b8u`-u_Mda-dkWwFdWirzjNvrkNvRgYahF={#W1o;7|VXo=58Ezhz?k*Pj}> zZs6*3y1w?2TTXxJ=#_V0aN#Leyzb#UR&U)Cz4Gl>zx}p>c|DQOU3B_ezYsa6`Awj~ z%@-XTIpr&-=XSh!-#dFgd__jSQeS`O6;~EN+k5Jk^qr@j^OCg}9b2|Ba_+!Oc0KRf zH+1e9eBh;Te933K&Mda9|F<{a`P~)!r#HR!S zTmCP5Zy6QW)@_R}pl~Z(0tr%RaMuJ1cMtCF5`sf;cb7nLcZWc54<1|t!Gi=RBycPF z-ahBs_q?;ueShw+M{BFms#>+Rs^(m)_c3N4vk!RrX`V%$Yg?8x34lU1Q(Wbp(yBGX zj(>7J0ict5ygzRK7oz|7E4@$uc&{h_r}z5rvL{$24zz`hTp4U_mYei1GUxthUU>S4 z7c~CP3vA?n)$}|^0f6(Ho!5kgph9KkD_=l_SRy^A3@RPKcCF%8PM`Mt42m6%gKwda zZ&7Z90ei6{i>O!>$%fU9IP|G9iar7Ws!xMN0>C0-oiTd)zo^Gj*WL&MVA-@#V-Fkl zLC-9UU@#`o%jTmmOY-7!YVW1t_dsEdN$T+!e6V4S;}X8ZLv zvj~}>cvCAr|D!o7F@2rBCTAiv4R+xtR7u8GHuY1Vt$KMheqMg&DlCkLZY_%=Rx$IO zdm=E86VfBH=#@jAM5F`sB!|o>{ZEISgyA)kv}R25>v{}KiMg0*9>-xuv6R5#;@sTM z-9yp)jKT3w%u3pBhwdOH3K|Ik^Sp0-n|dNBa1zGDpNnup**hqJ0{>)OXT2wKCHB$` zU)o>bPUO{QmO~PxOYG>;B+B#xl5r#R{W${V1!C&A165H+@muE(AJN`D6TVZilZE-o zS{yGoy?OV#sH^J{4S@6K;VSl0W59d&TAVUKGbVmy&UoOQ@UyuZpZ6|@M?a1fj@?Rk z%=-iAi?kl~yzuuwXGzY){lOwA0aXh%Lx&n;6h+-T*plBL?u@@)csADPM9TAo$fZ@A zxcHE&BvT}@8>NGy*;^UfF3N-G;Bs49TI%xhD7l4%$fkT=Y*bq>KYlXfKo%4fBmg|j zZcZL+uiA^TdJxr9^1WYUl?kA&aKLcfpyT?Sx7N>B5T3QS{+fob^^xIQ$2~25@Mgq@ zH-4Dmy&4zy0(AtQ&sBwCujYFnj7aG8M<3Lut*1ny1ZZPiXKjWDJsWRN8GH^y75j~& z)ibwd7kIm;NIZI-*M1B#cRlR)#UW6n7VA4&En|}&9zCM_ZpZK{G6r|Z7jjKx3#MIO zT`_C8{<1BZBwE_HLKG7-kB&udb+$zaeMvmve%;Cb%p8#RImZ4N%obT^Im!FIcjIH^ zP}eyZi{aCO`XU9b^^YLKyYUx3_e+}Jdkv3=)Rctd=yGn+&%})`mmxWCzk>l06jUff zv+JCxYwytJ4({M!IiIK7D;)7(KYrb8bRC`=c<$83pZoTv%fR`Aq2}XE; z4|;5BobJz_>I1Yg9B&Y^ah2-AH=t}Oc(fypa~@H@ezCBLglJc2bTh*I41?3 z&y1mnWD{0{lFoV4G!oW(f$A`5yu_O5lVZ1T;u zogks)g9#RpQA9tPww|n#8UUzpP^$wxQDkQ)Sv3%sKAiHsss>Gb{Ml;j^%X#Do}QlG zb04(ew2;l~ugtOcPUM}FH2aNUWS$LUFa4m}h7X+Lz(C~AIQLRpc5!m|4Q@YbSpFxX zG*G#u@gYbBjNwD(${h1#ZEfvvc(~s=W<*o)H!ldm5d9x`;m?+VWXu0Z&;ElKxXYBm zu0C<6|KbJpf98c}e|SOt@4UcW_7^X_paFpSuOcY93W9WR}8uF#wlQ`?z_PJ5PIlT5+ESk6O*tCw#hO|fJrfm#YzVfN#& z)is@d_8kEQZi-DHc4&nW;{Xh&(hMFbX-h1Oi3PAep2xLrT-DxxJl;RlLoGSXQ~myZ z?eqbx@~N)Omiwf&^NC^`nueOwMqgJP-f4E2u@!wvg~!3pv#rBnNctd~(6^u#99K6p zN|4ch>o>lXdqdwV4Q#+?<0XFRm&-}T?K0g5dCsb#kj>m+iY%GDuj&-R;$;2Gn22u< z@Nrp`S@``SQwmi)PeX>yY?^%9zKP6nDUX7GP>MiYu1G`xf&~d&T4hXvXce==nRI4> z*R*|LueloJlMj!-3Ko-*pL*oRyk74ore^KDoN@m2hAFFMcc@o71Wcxe`0SnBekfXB zt};G)kx4k8VlEq^0<-n!Jq$pkjLg_VCy)b;fks_HOspV8J{yT5CSwVpDwYOQXL07* zVkpuCZi0kxq!-Gp>}o|ALd?_Eq#o-mHU-^J^fJbFbkIV2@mE@%w@LM99~z8_AHVlU z;Jt&`0@nhRu0WhV=?2cJSUkw@MgovwG@&j!yR zlUg5)72!S>l#8)(_DwG(gjSQ%%MVDmRt^{k8PB1S@2#^M+sq8O_6!}omT;{e?{37` zYL3LT<=}hcM#wq)qL@}#kC@3+;{#T)YP6CE3KUCiAwf}l|68e;u}_Wx{6+satTL_raDR?qKw!@E12!(1ia9gI} zjK-o5dnF4KiIVw)BiS${Ox^ovyj22$lX2C3 zyHW!g5Gh5HA?Rg#x$_+pRYA)qpBbSHa2hIrbpJb6uI^y)ttg5tstCl<#-xh?L|4tU z30DX#(gi9e7K)(CFz>ESCA>ss*rMMBP*C9N5AYLPEsRvi`ZzG9DMhuau2HCC*|v-- zo9}UPi_Iybsg$AJc!Bczq-G}w1>r%`89v3F-p+LnsD&h^v+q$dUq6_#^q-%cIN0XU zslVZ*JTKR*`sppJjGynuD4Qpmhmq_oqDn6xP|aS7Cb5L7!WgDZfVO6&oB@yG&j62B zkUO>c<7sQWQRF+9ij*)E9L@58Re>7!g=&4mB3Do1(3b|$DsTX0FjWy3oROQ`byaF{ zv6_B%wvydy>vwBP@mQ61y2vEQ6m+S_V$<;n+vo%_RHF2BMpG+siG?3tu=o(eh5yNO z&3)KC-s@~4&A`U7n{VrjC8kNGE{vTecuw4YXyQ{3D*n7&j`=)hqt)kn|0c*uBhz|0 z2l<)LS!+Ih1K_9YfN(2 zEb?;r?$8NElGc;%$v34Ayl=Sia*l$`Zmi4QI?Z*O&9y1w&kDd`e{)iB{;NZ;kGiM@ zw|vH1MK;78(W6Qa5-spA_Y}Ir3K#UdBsIP-B zJw#v7ZI%CsFX{B-{Yl0LZ?Ac21zlU>!4U*xtmvET>-8PJ36h03odE#>Gs3WpJ==c8 z@9o>iP1bd{6(ozyBUm$sb!&V3oyh!3LD&7My5p6WmhWtON$k<+8-hL_TkGDZok6Nz zDzXQs8(nXAbG%Qqhltg%p9*<2x3sutfT>>Jo_%S+2h=t6tB<_=mU4s>jESFM_U&g& z7e$+orKU72*}bkVGA9I>R@Mv4ZAgK1^Bo2KE;*EGc#%-!#Z1MLQySxRIAG!qY2q#$ zh@aTALb@1;lWa$9^) zvsOB0lV{+Gs4)Hct94QO&TI?~4QV5(cu@jfEiL!XJvr|z+kEQ|E-x>c@HKv~FOBnV zyfffZg!S2&d(TY-T%WAT!Nm`_L@j(fKCbE;I(Q_R^YZdiU1_%G+zTMdEN-&o$ap?y zqk-91`@O1V{f7|@F6^tSshW#uDpt%3>V-fZ@qsPK)pJ}1WlBNkqtb$J?EF>hf zGC$ueB$J4?w^~(Gqck}&K^RBIkGtwTL@vir#3Ylbt)Y?Tk;B^qY=&0py5lm4Jx^hz zk#XTI;+ku7tIC)#d!fcecoAJ^Fu1s6C*b>x$fU?zn?PZfN3%jhSC-#id%iP;?I*?i z5!a!2HFfs)KBM(7lt@;lrl*}Bwg#f6i@9x6wK6`PKx7nU85}L6Y1*sPh$#hK+Fuke zUHk61v`sB8602=SsgOzOHrwIAp3D5BAH@D-rr#QZ<1dvBq85E_VD5&zY$@y-(gRc5D zOC8(tBYZC$%MZtc!HmJBevkJX?i4hZ(J~C?WFS#u2^9?4xRvH#84wu|U~gn(6bMcP zQwG{J=``%jRcIQ<y#ij6Ca+d2on4{w82f@VMQ~(0<;HxSf4TU0AuS7_ax(b>3!%S&S z&8cZD-=4^`0{fNbj41M=k`k%A^R%u?7#az{NV*y#UOVg z0OaI^47jxES@`(;WS_WO_B3#JZ}IxRHLw=Nsxh{6E--QD`0mGaoXbT=5}i`@U5eq4 zBEe@~`+4J0aH+CIia?xaP77FD@f}~Cn~l#;^r2XCTb zv8}a!J6?6~oo)!!Sd=Gg97~2Fs;2W=$NBq9@DO{l%Tm#6^dB;bOsg}Q#UqgeTkH}l zvPbh(x{CoeP0O3@C%BUrKL?@^MK`}tfAuujp+*~#+DU|v#0B4ew#!p~`*k?M?0fp@ z{iFQ6^SgNKG4!2!Dlyl}M5Hg)$`T-y#p(tJrH46MaUGM&Ry0ZREm)U=vF43>b z;FNw7yMIkrJ?t#-Ft?N6$NxTE2$$Mazo#n|=ijF5Klfk4rfX;N|Bf7_;OGEr5ytg5 zIf$KCfQ$ccauA0JJ4_8S=ixOsVKe44>;=eD zR6!H~YKD0cBM)G&Nn9ngT-9KW#oUcu%mGm|N0`OB%2H8nP&^C<6lG@x^t!EoG6IOBFA#jEo1Y`QiAX9kQ19^7Oak*5_mF-MltD{+Z7e>%WV?(HUQ(|H8dB zqMsf+>H2}En)Lpl*ybIJ5UqXo+&8>tvcsP2*5{(6sj8r*y{{!hAvp{`d(qmm)+!Y- z3Z#DAe;%feZvto(0?@V71X=rE6@zYHZ{$}Jm( zk{l+Q_#Z!+|JrPcSAdOQfQ|iM53!oL3v6?t00oR`VfKrx94uTcJQVbj=4OsA#tfKf z^2RXxFql!MwFS%;OMpVs#TteP9I&Q=cE1H;PMD#W02hY<2jAZi!I&M^G|-%#o0F4+ zlb?s1?f)DRIJo)$ho*u5$9p^fCw&-(u>j>CNa&dLguya^>LjiG8UWDoejji^<~vxS zJL=T$M_wzWDc#%2Py=VE%X`B2*Sbt*ah`(p6P@zL4w9!5=mZI2Y=MgB$mAq%$j~s@ zC|o^IitiAnNSu%)NGhb8^5uI0YBaRKCJc&{FfE;BRh>j0>&%7Il=~NZm2V+E@XW71 zXY;>4dAHV{$p+fBNi)%dOf zpwZCFdiP|HhupW6;$e{(72{f*LPtos)-ob9JtypvE!q zBJRB6nna&OMRyw;S<0-Au2strQ`ojdf=u7S0|BUPs@-f#o}wb)KIu>{P%69`3KN_$ ziXDbEIjI~jCY`umEROZ}&%*Boov8sb=V@D9z6|!1_b{gl|+? zlSZkY_kpa-hvWTckm@Yx?Q@#~W-zLV%Pb0I#jFvExRU3kVed#5j)E~7EQqCTotEbb z=-$8E@~`}vKpa7JRja$1lCafwS1K<>1ah0h9JQuKBSf&vUBd`AS_}lEp=*z@^#-b= zG3|VvM-9b+mjq)V1Qyb_PmCINcGmQmH#NMf=sX|iO#R4}9q|&V|B-XmmPE)bY%OJ` z5I=7>D?u;NTabandKUBko5+ z!u^zKHw5>gh#JATI#NA)y7lLn+*26i}uq>ZPk^*seI*TawLHh5Tf#Ad(g6;i{)lTi^z zTCr(5%WNWgf5r>!e>+YQCMVYcx{Ir0^DtL_oRG0BoR)q51-If>bso%`N;Vz-(!md# z^&43)&Cs}5&+A+n=<|?NC{mQg*J+(kd7TVVIHM+x!&-~ULDd>g6M-3g*6U248o4qH zI9}*}{#?x%-~Z5dA=^|I8M{7#g#eh8L-V~h%H0h*4}Q+kYQ!y6q*yuhSSUhoIf5{Q z*fXEVYR$|?lixq*%TE`5SGXvoKJc#6-zu_&%2rN#EAo|Et{{UI&QSgB7rSQ6Tr0s}f;}!g zKEbUJi|xuWeCZL)@!LV4ZKiQNFb1?*y?&{#ocmF9th&%9e2>Y#Txe>dYX<9*bO`f> z9-C5z`oL6t7A-ymoubyC=_F3B!2$6JY0;c7{f9eSL3h=6~(2FV~$W)Uez)K0cIbFE1SzUMx@gzbdKKv{FrYuVXO5`~(>bPbAov z-o%WIq9S-Y0Yx`wJ?4&vsOA)VQzj6^Mhx$L9k*3g-gCV;P*2uVivNKT=L%V5m@&|> z>-A~3H#QdyqsMM>tkp6#*P6k^$K4)Jw?TpNQT&xE`D?PVF<%26oK|?-7f2zZgPRCsRyM{%0oXgna&V%-S`1u^ zq1@V#4kjVg;O+YjjEX*TrRw(mYy^8WAl>za)$|*s4}ej0dRnoyOcJ8G*7I@Nxk37> z1o|Lx&P3O90Szx3daEL%%deU9NY(bQL1|jcQ!4&b*twLknsqv`Zne*`L3iO&R&zSu zuUJ0xSlj8-u3?0yG1Zl_7%owAu zuA^em=1wvkOtCW0)lO8+OrDWW5w*c685OZENa2wb3+IwqLRpxRmriP2dgjTBEq~pI zjKFVIq4jvzMBUv4`0HTit!xq*eJ~oLRvj@2wZiLX6W6h#77fIB!iM_A!!z=*z}M{a z_JMd4XnxNbx3ON|28qqJRPiDHnbxd=gIMe;7sii*b0^`aPkxrcDk)Y!*Q}?A=S|m| zdie5KWjhbd#~_`Xp?QlVJpNAXYL9%jGN{fZN zMSpWGd(sAdONNquSBo@XiSr4=^-|hGa+VwW!E5);k>85TuXfIoH_Hw`2M{kDb-ElL z4#O1FKO!3mRPH@v84i=W;PvDC@MRQP(aeIW*@S~w9)^63K1sT`C zTigt+6Qy%U5b%IXg^dEzx-Lb8(F`o3_{|F|FhqyttACFF!aOY6w11dq_V0-PM&vK% z*=h!W|6K3b_-Bq0`@=CE|CM9jNdD%Sod2g=)g1gkW;b+yI7a^8zR} z#;&mJhW+1KqI3LiiO$CTx9kSi3*F*(Pjnt0K6XA%3*-L}3m#lNTk0I*r0;&$kF>R-UYVv9XGq<4^0cO zq~{{LVG_9;1tV3OQ-#|fqYU~KXESK1fAGs!7Lfonh!X%tX)vRF{fin7xb+hfdQR1i z{1Jfjm_1aNVv6d~zuM_<)F4EVLL9k%aTlPN!7^azTL6 zn5oG&pv(*y(Y@WB1^lybGrZvd-DFAvxZDJQ0?#~L9Iz4uDkouD1)#+S;9JP`^8<^_ z0Go`ag)~sx0(4J+(dz*e41i4~JcI!Nc>_kn)YKk8a0Y-cd9Eq+{dqNbj}bOf8TCSK z5PpdOT@+?#WKB($r}PstM9=YgjNy$lMOb=0Ge|fBxUe@bJ^?^(0s-vTUi|Wyz^a~@ z;E8R=grmT$1O+zhkk$* z=ytRB)1`b7*<>PWu*vFfoYc=2^v9p%vsC>uCT&`b_}ePD&avW|(H9&=R1wfbh5?$H zN3*RBrh9}J8{9yx%?mj11m;qGQ-o_dI0AL^vVNoA#csT?sQWVb(V5}8=a@j-7)Qv>egSgs*{?mvj7z*j{g@U1I zX8vR@MhumKQ2NmET5?7s*3Tm3T-_>Gp-E0yEWH}7Si(-&Ka5dwdgwa>P(h-@D0s${ z%i(Y)ky_NTC`1_{x0F57AlxVj#R#l`n@TQ$Tbf-pQk_CWn*3bY1)e`lPqIBha2VhS z{2AII#hx5cuOj>zqe-l-l$SJEG9P`)%#}SejxaZC%B7K1IGQJKZ>quydpYif*brOy zJ~1+9za1OPU>~%Oj|nx&bgYi55~E^}wDwgc!iR_})5$t_5N?1(H!2Uv9ZF&RR8(3^ zUQ2ONx|D(p!iBSp%8QB+tkO$Il~gL%NZXEc*H3K1!5*e1%|tzq8;8dV_6`^8=Y`-# zh;h)h#ly?g6{^qR&PdKUs8Sy=m1S{BlTs&*ESuTZBl9OSQ9K_G`I`N;?M}HT$mZIBO|S71O3PXT}bs_S5zeF5NLOLkWV0!Y%1ZvWSt1 zElJ#oYtrS5NoJ!+hSb@9bIckH(f=X4q5s1%|1LPd5Pfdwk7Fk+yTShn0KDu+>3bR2 z8IBrSjLnQb1PP;PDY7ZFDNh(#)qh{%3+xL2eIXU(k6<4ApMv=x@6~Y**j2WFGtb7i ze`Plg2uS~6bocb#Z~jUW{SW^7k8&*7dOdMUzfr>f+iscH7Qb6U{r?WG|85Do0~_c6 zHs+w$X83bI%>Nt1!#22xew}rMbN*v=_j`f<&)@HvCq@3pXaNSeu#8mZ-_G^>-rD}l z4K_&$0LsdX%h$`%H7+#9)Z@ww)O@QYH8|C_%TPb3R%n!GD<7#nQL`))EDbBSEOk_W zS?H(zD*{QoPrgq{tWYJl&TzY9kOJM5q``xU(iXEK^i2SFKW*Lkl8+nXhxA|MAEJcI z%kuceIAu9C8&ofnEnXsTr#s)ib5%s$qc2Ij@QYl>KV{frcv8$I-^OmPXIq|{ma0`D zU7=DTb=1jIeO!`V+$r%v`#u0mbV!y?k50-mZUQlTPi;wUtpu%vP(fJWs+y(Tw&+RT z2XXfz0~IU`{ed5K) zc9E8bj(&q=RdyB4{D-O!B{(H*ib;wUIrEk<;k|jJxvYhxc4rZ3rMlU^+1J?8gvhdG zpt|oQsWZv9-8bf!FfwM?5>^Gd4!Pg!Mi+d6R|4yq6Yox5`VL&C9U@r7Vdo+g=A8B*76kyr3N6l)=nxI*=P}@@E zUVdYIO7!CTh0FWx7u!O->m2LahM#!5TZUW4l=>WV3_~`=-cmoBJ$gM(110`6aFz%W z0iprA@b|Y~K9pUtF9lZ2uj`kNMWb`uLXdda5X`hQGyEQQqvOPb5rOV}&UD z?axmk8}AxN_4#4Yg@lD@hQ5q-3fCf?W>4dGpI#Mvy&?WXJXL%>%aUD*zlK?soAE_C zi;d7SZ#!4}%Rv?k?N4)B*;+Doa%B80jMY32b{{u>9$$oQWpANxdlRLz4(mI4=1ufo zhLjMNvEVWZq>9LgEAl0uiGmqR38QJw@!V-*(L8&}do8J0r+KEs7sd1#pDLb9Gb(r` zeoN@!_Jj;@7BTI#1=E$qcgSPPuVo435N5hj*mDRAbg~B}Cd4~K%PAF-nk^44cP-q; zD$PUc9|jzvT3DZ^AdlEK#8)C}Gov*_i}%%a=oc7~>n+VSExN`dM)^}Ka-NSLe`*+A ziRXQH`u_14w-@(IVslZboF+55)^2B|4S&6mv*!xhHUZ-E&{s&6LamX_jP`R%6~~%s z)qb6{UJAAW20f#JJxy@7N9Y=8J0ZSDs|&~aN?NSi8%@SPLbIQ|Ac%;p#$O>yBY3+= zzv{8`B+PNND`Pdev8WK1#+thn|{VGL!=i?!S8H8WR)L6|6ZJ+1JXN1*NduVGgQ*eoZg7j*N!;`6!42xh%~MQ)Ww&VW$}h;X&)mo@$ysfnndh03 zS!$X0x+c2qN}pa#&mXRP{ghgHhW(C9NZV8PLVd(~`5KF-hO@C&bXUU)g)4BT985U%;T(EXYi`>^Cr zcT&}%)M0ojaxA(ewiY(`QukqX@pSdAO}BgQ#q_Gw&2L1f`)5Rd{s+;e|BmP@j(;I~ zb`}62g#=ALBwWQ|iy_8k#Epewh92ecz2N8Hdg=1(;Ae^0q}e2G4$(vY!&o&DA*@_I(bicZ*K9V@yo%mj7xTo3!k@jf z9~CPYKV60vAw$MA(Op$qngg{^)TCF0gA)AC2p(y*!cKeqa7VUfVRmxKzVmJ6>ze9F zd+o#zX^k&S-Zz{sAGPG{-3cq4{qV>Og`YtD;qPFC84t{Klc2A+zz++L-Pmb4y~QWC zS>HgC=XFF5h*&838S+Hu$kIol0`(l=JM(W`*kLH0-JZ;juZb75;JX zF9#ZC$LNHE!IM93U61xzYbPEMHY>WjWEpH>-<%sQpD&ht^H;ZJCeNfb@}~o&(F0)7 z8fk&+OtYJ)Fd6UnXW(I<(G7@0=n6JoHh7cEKaJ=_3b(^+U&1QQ(9(&OugMU;#W%qn zaFL;=v1DMK>zN>W^=7lBC|S?|dAb55?o3t^paj>|%W&%&46Y%adN&NukLmxz22cJT z_5m6Heb%mvb0_}|zlK}z**#rFbLTQ-LJlZJxrIMlF?^_I>C)Q!8PQUahA&=&MmKrP z8^ztS!F1BchxtJXNl0~cA^FlXU>C~G?SBk=-@&))Q^u9*`|hC)FIgfX%%79RYXv!{ zCZ1(Ll00pMJ@RpJc)=7s2s*ViE!w76tW#mk|J1TlZ=@#(xfI{x%#v0qZTYIB=v?Nf z!?UxP6-UArxUSqLKS}R{niC&#an_w!&*x`Sch`{GmozMst% zhX95(zNM%~$5n5G$Je@{r4M(`xT&u$M+c@wFQ z>;&n4Z*Pen!)*OGjKnggUu__4yCtYH!zMO1u0pgjefB&IshwC!(;Pri{jGwZ(oef34*+$d5vCS@DU`Vp=spzQ{_(vX&YBW#ljf zH+dVd);812YNS46lE{Tb#)sX+O{b|gLiEaI0{|Km8$a?DRSLYtGO|2bN_7#QjC@sQ zJiKiIEL2t*@85{d3PbdN$j<(ht;POl+1h_(XPfuGv$M~z4cWiXqW;gk!1RX~r2fte zoA-b50{R&M@Q6*7Dp#s6wpzy1pF7*5Gf+fx&k{UaQPnELSkFX1__j}DEz|7i9eB9T ztnTJOnNIA-(Czx%=_7cHuppiMEsk#T!S2^xDA8t;? zb4N*o{zJ9nB zi+iXS+f;}*s9E2R6~PbjxR7}NTOKpz(#uuF!&SKhzEiY7o9rJa%<>K$lcoNwPt#uk z*l3gwV`*I#kLPc|owdLZj5BY#@{ieA2iw=IbPX=#WhqCsE1G8kyaqB^+ZUE%$kJMD zx)&pbGZ1q04M!tS1{NVxf;5)Xy^ZFWIzDYn8;j`Sn*73kjm(FRF-j?wCi_)&bW04T zFY#$cw^NGB=E3#Ku@bajz93^#nNKH-)s|O;c)J&uA+o0iYN0nO7vk~w5vx=ow>Aga z>Vi~)6DgR&=9{0cH@o@2y;Vurx}=2CDC1I*8$XW#Crax;eoXEXy}ZTw`0H%j?tY|8 zRk$|lFt%h9LekxK_fm924*oU@hE)r|GjH}^vNfn+?zxt?-GvMto0~Yz3O_2*tpy($ zXR3}NOi@cV2<8kNvAYSr)LPIaH{oRaBqhr;@qRn!Of9SO6so=k8n1epiEq;No?&98 z__DH$DQI!W*2*;tum@sNAyJM-JNbBbgjr^*Jti4#%*9z4yXI8^P6$S>zL@$y~P!-4z44>&EFm6U1@0xV$hbbow`AI_~$XqkGgT>zMDn@5i@NS>N8I zl&x#CiUIl{pKbBE7B#qd`9f>qQ?wadmck|)Dd9mTi=li8dYfP&PorpPSuitA6Gb8C zULev+DqpGuaVSPCnNhn=3HM5Gd?Q7yGda371BXmns(R#?Txij&p47}dTs{VAucym( z@iS1GL^Cyh(ikM?A}I8S*5|r#E4dQlibbu_-g8xYN~dJ1ZBP78&~Y0^2*+m|g5X&C z$yleGU4bT9xUF<~s=mk*H?z-1J}w|7Mkr+jDZ$B_b9}qu(5poH*t$-9aw0>i4Mfel z?T@EwtCv$U>^_rf1G;cRF0db(W*BjpeZ_$=wUP~nft5ePTpm~YVmcTzD)@Cd52P+8KkXI=chZvRX=S~Es9+n z0XYLLI%Vwk^jxCE3WJ{9mmwVeJ2Jcm#6!QJ2$PiNdACA>Z7sso^D|RXVrz?XZaYd9 zTr+jcqcc!dPDl}?`q*fNC)J;=k~+dUS$sd7t&}rfB{_*D=_A#AX8E(3_YL7({Zt2!NqPjamG+U)4mnV&0JrU&bBgQaUS1zVyt+J%0AtjmN5 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‰_>RL@_cvBV@V2jxZ&NH}RyM)dD zgemM8t7!nZou0O>wMP7}j->x5pL3T~6&s>GRO%5EHZkM9y&TDY*%Hr(l+?&~uW_j= zN~&(Y;n{?VVN07H<~74ZsC~SJLdUBfIUbJ<{$P7`q;{;>XOrt4b8=pENbNqLvFxt8 z?J$I}*Mv4d}T`y&p|Ne26H>Kq4$Ty+O(ahm?*?&2T($ zeV>1yd54t|Z{?F_yIU**F84jSUoCH&e9PeHoSlc7lbiFhN=|fyv?H+s7sFc;{|hkv zva#~*Wtkklm$>`K(A5d$3x?;j6oTK@K4EDujuZo{F7HDYs+)M#Tu1`lYa{w}m!*QV zzs1g-UUeQqTpDwo%0O}mT)S84a8W%+MH~Tg<`3fQx9jt!O5pKZ9xH+p_McxI>Y5?t zfh5rLjX#54|F1h6*aP^@C!vdg?y;*yp4~HKJ9Me`eLD>H1De>AHJlgHrZGqr_)V#z zd}f;N`8qs~KCJf&p8Lj_Y%??1#6o~7{ZwJrpU$!Zu1OnL-NMg0<3V&(?72rk25&J- zm3e5H+94N8__JQ2VDR)_hH%%}o^l>A%v8Dq0~Qw$!8-tM|t@@>`^(K$8xLUFx`c8Sl& zg|3Fh=(B@uq{@Hug5%#2-R%#eU;Q_tcYgi{(Hp=Z5F+cmpY2_F$rQ*+Mvj(pXH8lz z$|QnOfN0Lq)b;guz_ADiysx z)>hd#p<#P>DwNpTH3G|Lkit=S99|ECPp~BOzNWw&DDf-V-9uUK^N|&04B6n4a)*&0 z4O(YLu0fDZaNgH9T4qTv9`g7m5mEmqok4Q3k*MebgA?Aoj`d=qK|qwcC;%o_&~+>c z9%-A;cnD4tGuVAwpmRDsmeQ#t+c(jfHE~0W`U~xvvP&W*A_rsYB8=nw)EpdZO5Saz zUYvTgFWa?U8f}JDWF|ugl{iCg_{Mb^g@T8;w=S}+d-rrbh`6}-W9(?G)WltQn>K9Dn3!1k+Fv2w6F6U%Hqw7$k{K45Af3(TSK56d2Ekv%oA|;}l~wm* zh>5KHx>hr+wr}^*)`daD=&66&K-%|9@UpKs_JFT<|6-*$h&yeltv5i#K!B+G)GEvJ zWv}kn$+irA#;(Pn9WzZdtavL|ll57h`>c4%dsl*7EFjMYJxm2HQ1rSLTIK4Dtp&SR zEeV*;X(TZY<|E6K*6+RO#ik4JKE_M0eAOY?)?6`E%Bi-jHS?IR9E`b0sQDzSW~3Iv z%*73);k)qDQ`0r5H?KKP1_o5d){c2zepLaLeq4T}9JqfgW@L^XYVR5xlp2KKXJb!R0gLUIY1$IcCYOr$BN1%aOu^ zgfQ^S{DZDl9=&&oIzbWOcOxf->d$LV_2#O2o;n{|8Z^rY*Oawj3VPV$B-lKTOH=Ti zA|0ahq*{Pt#Z6^d&L4v5uKsXHnoL1c#j57FBXB%l>dVxa*(=FP&e?vY@%4UsHFXpVDXs?U4DZ)V~T<2y*mzLQM)!Ie$T6!MHjCJwvsRig)4ujy^z zv0Z-9)r>k0?jG};hiKQBmO_?7~uiVB9;g{OR?@I7hjtqc~bvsfDRJ;_Ufl zOYJHym^Im{qt{5G$xcUN8C2#B+IuV4wWNh2v*H$%A-g<%+mK{%$%`}4OI z8a!vIi}CBgOr+W9$_LBF2SwrDceSZnQWquY!$)Ku#v5C0L>!~V-XGlKUh&pC|9sjS z^YE5XooKD3Ux$48e-A*FyXIHIU(qe44wZR1aggecyMKewP0ob)Wl$ zXY#LPj~VneY@41n)Q_^1X`l9(zp-@8-N19baQpDW00%CABUe4=itZ$R^7WMMH8jml zNM*QtkcY}zk`1uYQfF644|PwOSh&N#F<-4pSxk&?uHRR>ia!Q85@)9cjuU=t*qYlyw^H^6-g=CDdcdXu(*LC zCs-11O|k7p7T3HJz}F;7gs`w`*(JasPl@nvw%yE#V|U7;mHJ%s)BA!=5L(;^ha{ZG zxU5`9_5q&Ur^mlQ=ae|xGgpk*S*dK?FOWD+c_X|ThQ6DdLR{rkfE!}EYhsen&{OF| zOjT1kUvag-*@$?k(q5sUi`;5poZfxG0Yi%YEKPq2_6^*E6H3eG*;2)U*e`{s(^rUg zn>_cQ#_b7#=XPflUcPiQ4J)_<7yx)*4IW9xR7fm4j>tmy(C<~D{6l7^+vOuo8;G#x zB_y=vttP^(!IG+MI_lADsIcb1HT+YGR*XSt*|C6#|WzHcT}_Y3&a$Xn0^OM?ptnF{c2Ry*NDeyDy!zz*d;ZCfZUOL6WA|(NdiiQ zlE{DIX<~WFj%6R+YF)Co;OtR{Hq!&j>>9R;b-3st5D%Gr5VYFdR%9kWYgDRKqr}|l zFNq^f*w$DG9~3FsW35n8BXd_>1%}tpq3=8}nxxC~Ja>+#1-B@tAf<)i9fII6;^Yvp z%Xey#v`xTq?BUaiFz?9ZC&KD{UFYksDbn5Mlg$`OWVUXNsGej`-qi5hQU5Y*{Ux>^ zf7oU?wn{KUa|O#YhggIIMV8lSQdBfAM$z>ia^w9IL(@bFH9w)ieApMA4prPv{G>rJ zdGb?~$+@+a5m(1Zrv_m#_bFI8QkfV zDm!!^CbAw3J|f(dbvl@N<)U-Y0w)jxr2w)WT z3Nn-?hkm`n`=-(2sS|AS4P3`zZ0E!=tF=d!YhAAxI|(U=W}c^CX9cT0Aw5SNf*&A# zFl1fN>J*{Oz6HHMPHY|dlA&z@AG@%J4nI9%XbyqbyFa1!+YpY1c*MnH?Yu?&7tCov zjEX@6^l!?aa+kN|gAbi>&I@nWbo<@(z;lfv(xiyRl!e<*UMiO0Z41=>0{wKLHUi=X zGc-4fX47!+J#V&*bkE%+f~B=!An-64t~AioxYJX>Bh3bWvXJoZMGS|Ou1z}xxM|)R zqa)Rov#ZS>b4#WyS_E zD0v8kZVZX1(w@Qvb1(6O)wLlBP;}UlaB2A#>mHqsswbuJRxGoo@}c9ov9qQD$-%R; zEHwPFw)WJ#!q@38Fr3$;MJPN*Wl~5&<_7Cq?kCu5B4b0pmzq4i8o|>In90dTmtm-Z zeX6G(_~W8g4!33G+QMFi$3knfQ-6VczaAL-g+2Ua6qX-Rv`53Sa1J<=CFRiRl!|Id zRV=}$BbOhci%~1>{*9Gy)%5GdPO}+;i5@A1KpUuiFgGTys4u7(BH~cKNh=Pc?YijP z8A$OgmN<=FBR;iq~93WzyWkljN*B23f{WUJWpqJOj2aslu+?gNe)EGFm(z zIhlNU%gyH&Z}m~%SW1sutZ?&{#Mi>{{m#%9AXczCK+e_Q^iE{aiVcj*`M}-=3@WQH9^nuwS zPnTZSl=vPCVsFa-OoHhZ9il6T)^8Vg3}rNZ2;4D`11*t>Q_yd`l_V5FSw~IY7u*V-wu4dJZ7GT*emjdjyD8%LXl74Vd-~m zphW$po5YZ9qq+B)%-TW~%$J+`=`#`EWRKPx4AA*KI5%8;s;J*vvfOn zg%fi}K@J^S$e-aM@CKt7Kp}r42SpN|<(Cyj^@`@>dyStjVnBGj8j__6($HU^>kW2v z-U&V~85pUmdOvgD;e#hA^`1|&v5(?J>pyc@Nw5e#=%&>X;+~*hLH1#5cnaWWlJ){E z8BptCII^(gVxDu+sqx1r58h94(mDcjmgYs^5WVg|?XN8lJ_tC!2tQlpCmCf3HY;2p zmtCAzLy&A5aAi&f>W_$$B=&x}^?P@wx05OA1BC*c#kL-omoNE{zMEmY(kw|QKq}-bWzPOkunJFrREbNd%4Aq}{#<9LR$I?ovc4p&|s{pN+|e@ArhKZuU~H=<9( z{)6b|?0|^I?7osNq`ti+3kZr2t59Tx3t)YhkcUMsVDz2`FMo`@L#=On=)-eY3wo90 zs1&H5hnoa?{Q_kGnv>@t@U5{KkQPF^;FQNE`s)KnK&frsLDi7jR>UasUDC(cCu(#; zDs>D(aoI25%JutbF9#NUxBtYSa-3?mZN*D`kC{@e>1jJ)Yn%N@cJl>iuJzV0P|VOT z(5**gx1Qgg+~(-Q^%+8uJ-cMeXYF$+Ufd(vk_8;27it0*;({px zE)w&>_@oxj{bkR9R^5Mq=Y(H^;W3WR9m?T5HwZhSMXfeyy^3V!Bj`UFuqSM=%m0xr zGek?%o0;D=N;FXgN3#!hna*GT1?nAu{{r<;ZZad+Tq1%11qXsIdMyAGm1+VY7ZCloeYM1SC>+#($8%--LE5?y#o?bsji?T>S7C3q~*MM{aTP7(gSyc z`3pv7EJdq2v3Z`d@e?b4IXa+isHj}&Nm*1czOo&69zJOT0fR1BpljLSlFC32ad0?d z7HNU&&mmc!h&XOQu%0I(33f+NB+F^la5v;7fN^7vRWBZk)qL9mFivUSf^9Z|lsg<> zSooSro*RwCDeNln;oJiY`PS^2&77JtBN0=le$Z+E%%0P9sxD>4eXG(lqc;ijEgs3UqO(JL^AyZf; z3D-AYXubG;W16O`CvVnbA6mOeWhPJKDhU5s(1{LSlo4O{2^M7}=s@0zmVFk|#(l=v z#TD|&~jffx6p}S(H`x=9@9;moVP;jLk{Cg%NUi-Z|oTdi}&?I#mw*PwvHvxl~ra= zJ5(6K9S93P=tK_1a84&1p>iuMhsgoMq_vwy9I>g|3lvG1`&T?*t;y=NJ=y&rND8h6 zN*>-mI8~@1PUh11^UbicoFr>6ULR&z5F%M>RXXT`<_Pb)fny3ZhPN5+w#rC#*q1$i zjwzeV4MgN3f26PGKtd)?nDK0GN%Y?D`95$f&a`X_GnRx*%BA0)e9sTlI|8EmriP=p zzYA~$4%1jzXk|dOLVKe3IF;Bt%j9K0e7E+dqOLcl2A2wuX~-S)6{6D`pIb!^sQj7S z>27hQxsbu%h;9lX`d^fO-yfwf@;{aS+#e?qqtX8;{lLHTg3ljb!2FvR=Kjk`B%=-l z>W-{osF9pj7DbBh5nSr}mYzn8Mf%nw+j813i;rgla~e!TN~Kcbj|4f>B}&7Vou!*s z35RpBIWB9Oia5@Z5vcm00p7>4PEpSNF2p%g*QFV>MPUOS$~YJfCg_n#f4AD@@io>W z8S76eH^vG^TQl6b!h-q6DXz9Q%aH!A9lPLo0Tmd006)C1C?xT`g|`cIB@U8+IZL(q z{NwBnil%Pv*o161Q4xLO54Q+w{eRed6L=`Q{(pShZY9zt+L(|f%hkWXSa2zBrL_KUU0|yu`%Sa}d%x#aZewOf&KUGM+!54N~ z1x7ln;kd4<0{Bg+^-;FB?h0kmTW^S-nv=gCWhSZgLLfro<%TaXGU|=>d9x)gtD8qX z$$O%0(rs?W#z`{{A9+@mcjIkT7C58&`Ecglx;+WX+g~V_-?q}Rc-1@zTVj|-rfUHl z>7pO)(|`G(5*Oc_b3t^`1M);3cH6Xg0>S+g7y`(K6uT@t+@z}Pn zs`yc4m3+=_j?$%?H}0oZ$`cl~Rb*^?ou6%0Ir=5;S8KB2*IFo*5tse~_Oehl5 z3t~pJ+%>#6U7q<=w`7w!J})|Fn_D<>M(aVajC*zkYTxHWkBk;%_Ig}A_gSg90EpW< z;+mmq$w8^joXvEdc(X-37cHp)j~Qlb{6a+Iv#z6Z>P~%%7QC}L@5Y%AVh70kQSWP$ z2Dl{8^@%Z7*f$`vP7JSK15R-CW~yuI;UX?aU7{L|T$i-XQaw{;9lQL(7ubDarcUA7 zBL^QPGlv6r^zktl@y`e8)`V5dn|gM;m3ju>(@_BlNR$D>GoJU_g|vBDF9LlU#uINJ z{{kzVNE_3=rMd0sr8xcSpc_N6rwuAy-)}U333eBp)W4E;syI;grB_PPVtw_>`({g*#co{vxHpV14l37~UYl`?K&@SBl^V~wgLm8DterNCS+%>HmET6Mq zVWPR(?*+I0FAV%doW>5|c04wYYBY@*Zq!4$JdTjJt@*W9RZXByBA=@t$l-!LYtQvI zwWJBS1&OVyf^w-hTt6f)xw>< zQ6Dqa&R!Cat#vJVbsTk01H9C9InOV&?KCI*>U+i$Nr4ORT?r{E@b};3b{5uuqN4b? zz&4z}zW|Q|RpLJ7MK@EI5GYH(k{T$`ml}OUW1jD@|A}Lmoy5~A<7JOpTlCf~V}x@D zg>ra#;Q0$`YOOGR`d?spJNG_YV~*4F#YD>qV0B=aS3L*H8uTnzEb7Q zo3|9lKkPyl2h9`aKfUjA+@`Iv9a8SGqWw^JO1Pvec{gSfaY$!pg=2OLy zDjg+dkhjpT9_zxu5H_DGV0*G&qF$5_R{N zsBz7<_Mn?mY7t>Qj!&Pq$Y)+23ga4Fe~dyv=Z+%z8*pZjT=@0pi0;cm^zqq<-pD>l z1bBd8&tS0Sm7hW%8wOf*H$SE!vIgbo9lrcEonm*HkJj;YJqBPke785|bCm3mcq!NtdeYG%C76_;NCO1Lo}z z;c*akW0^2WGPr&&h4hBn3}oRqNd}yH<{jGmwfNy9iC6b)@PH$s4ltDZoXb75bG@`0 z>XyQG+46pHCkKff_e`2deA3*k6e!VD7g|lrH(OqVMJn7q`+BUj(cmJHgMXhtuPQ$} zO7m!1rT@U^>czvvQktth*F8YyyY=45(agL4Euzooj~y5EA0sqS z8N7m~SqAlV+T{|=<~g?p^IHncQjR{y22{IclS6sMpz9NnryTXUp=f1LIx} zMSL6{-Puxr8I-eMN9jp-=|CJrxe-EhkSBOT19!)dhO30M5bnMVI$)d;Q7`#0{f)=a zLY=cK@-{d$#80^1X*eB^SFauQ3gpJFh=t_`&}Zo*qpq`ilo-!4S4rYz86l&T{MW2*vM&YXZ6{qWib1Z zYjjkJ_PnTyCjl>N_kt6a_IM|*6Uk<5TH-CQq1 zbRT$or%!@tq~fi4_iY|CbL;Mn1v=2LQ&1~*A59nJKK$VPdSbLf~*RvU%Zx!vyLy~`)sT`cCR$~Y8dkrQe-AF zN<^?(L4RDX2%;@lsR_L{O!oRmtSBY(`LWj+P?QQub>yQ}Tg z5#6=j_*&KCQ)kUpx=e!iWnRG7pdHt2%Uj_Sa_~m}q4c2`5SkRCdH_V-h1Uuk!P6)nJuKS1@DZ6pLHTKP+ z0plp|#Zjo+-TI7spzsT9jnA;|^}!>-PH&GlRUW8iRD9Zdpjp`TzTGMPQRnOd=Az=> z$|{g@oNmRpChFpf_if$^c8?5~-&I&Dv_*?wOuk33r!~V@k7_gyqB|z_5qClAs({cX zr2F`TE+NM^Qij=gy0#U4fd!7+RC*%q?s0YU{E~jGg*x2vh=GexS4!>jyyxzdR2zgQ zc&twlQr}rFUUl{A;d#9)$Hdb*G$Rhq%y5D}Ylsc^O~iy2qC!kkeDSc_jlKPfm5=p{ zefVtlk42s+VwM)JJrRs|S?@mVOjD#0A`UF>b!p1@_()@`v|z!$4&`6xS16BG@DU0#sT3AP(q7?>6IMY|A>3|Fl&6sGaqqRW~{2lnyQzX#d!s z<%DSU4)QO1Ovni0*JZS^yJ8P=A4p4gIM{bu5x_V zd202A6AuTsz_VFmbwoEb^-$Y383BFs`bGKjfxTuLX4_4_FI2z@7 zjF@}MYEg$0iI4pK#sL>yV&g0pwVRVWb^Qf%5$`+qP9$hJNolOb=ZU|}7;3(5U0rM% z?1H~(s-pEm^%+bg(3x-X?)BD+;<_)1-iG)RYtjk+hsE!OBYQXR&xku3EOOAGSKt!m zy4z-s=CJuvTY6skZwl}7T|VswXAy}sc~9@nw= zwU=wlH@n=E=(wpa3lD#mDW05S%6qwCyBJ@*nN?NHn#g01{NrM1nTW0x*O?{#C278V z-D?UDt-k9dOnG)bGVc{ft!bWCq4Sex!4wT}Sgqu6UPq;5=Pr15xayVjMuuyXF%;qX z;Kldha`tg`_o-b=>bTZ)KC}NtI>u~?oV+a^ntSgmB_pE@_s%v$-qQDlQ>q>RmWg|lajFQNrfC0O*@%7BYn6z&7#yGWs*A)y2 zG@Ngw!LvLzXPavM!}Vsm9Ae2_pWk&3tGuOROIA!InGd9cbftF&3%Yyxu@Uy7T)lh3 zldc|&jNDH($>Oa~m29Xwd^6pC!7lBj_Lx8iarlva;zMF7BF(4$L{9rDJ;}{lEY)MY zKHNG#HF_6~ssFh1Zb#+&Te#aPCdu)IO2!hY z87dABG9PHKyJK+Ww65@iodOHtO}`{wjWoO=s{xGKu6qrrU)L~GQ+$Og%`)6hFON_l zD0{6F6cv6W>enjLyGVt%ZE*V@`Ziv!1xotd3-~*)THAIMrC3uEi#L0Nh&=h^Z-wQF z)YUnQ+w9kCtW`eIbb%nRT=YZ@CYm0(PQ&BfSok4NlKn-&bdIhsuv@_;NQEGUr`ty} z?_qAH#anF1I_@KIT;*f7{sVa2n@24LUb-(5MQObQs1}QPF!NRRTGX{ecZKYIXHCrL3qC`wXbUR+UPq& z^H=0L(=OiewSBjy{ED57!m)eX#%(FWwwpYCw(V&S5-%1FaxEr(yhAdK*;ZD2a&e4; z;l)xDn2c-jX2t9_Schvu@ya>fb+r0>_z3ihK z1Fd~_ym_iJXo#p9f_!20{<+^KqtiCi>aW-Vus`HDe6=z`_x-9gF21seJd*3vUS-Lijt5#pdQ?)-4y&|pj?1_l+sKLE{o4bpHxI??*o5Zp= z@pe0&Al1aUzNK17<~8~+E%?O$!0N+kvzACKBW7D?ZgKuHlUr?!tP(}%ld-{PT*BQ) z#V6(~6pOmH1+^;}ENJuXHZ**kx8Tp8yhbf&$86?Ru`7SOsQ~tHcJw)@)H< zMRMBiiBl*HaMx5j76xy-w%cq8HqqW9Yx{GKgzb?}PCXpnemY>@`~A69ulkneHN+RI zs&AYi@4jEQ%=V_Z)|(4=b*Ohsx-Q%bt`HFa;3SZrUx{D9On4Dx$^<$4qYJxB=S98~ zET@n;xRNWYEC~}%)8#RH*+anm#5TjAY>xb~SPY6If?HSwH`#v0_K~7D# zE@Ck9fWdj^w~scsR?N94ukWMKi*;c;qC&KRM?m1}CEc~ZYUd;QDza8z`OqG_{7yy% zd0h7ccXpP8O4I5WdEu%eaYVO?l~#Gnl6d)VY`nYH#mDwc-lTt+s|V#madt-t$^R+dAYTKF`;@ zQU9RzFt+vFE(h1bkzO0?aYF)M-FS{a?tLd_*TFn1@D6UlhE}j$DcrSKcy2<-{H2~+ zO)C#o4g5Ns7x`4MG7@aRSP4)mW?SjpmV*W+t1mC;)-MM~HFxUfj=3-w9qm*5kQcX# zV#d>P_oif{yVba=V}8jZXREO@e$=HL{^PG{f{J_HI`bbry>;cP>2TFqOR3&%q1)KxWF8r{TGv1Z)H9Hb3_kdAv%3Fq7Q7FLUc_IaQ5Gg zB--i zV?L=pw(ZoHg|7-)RTEyjzE&%Xvt_zH9IiJNFBu(5V7O`qO|-)vem1{JAgryxzdYeo;jsF6RL6VL{e!9k}YonY2`?~4_!4cOpUt2=5Uy&p0>t5e-h$47Y zE&EzD;ou!7T#@Sf_~V$1-l~GJAQq12&M9r>7)}6o!_iK`RUSQL)Zs;5mwkiH z9b>%rAqZ!N=BE@GP#+~k*4#F#dNrC>pwbl4-qda;Q?$2!@XYwFvi_d2uJpGPdNyZ_ z&P2I=7_@IenB_&bYaz2Njs2^d`H)Av{XUx%ukJRiKDoG}H(|`&Pw{-?ukY+8+7-e; zN`|ZCzBa7d_L!~yt)u1&qy}34gmGh1csh;8*9f6*{?=t_!4mHzZ*SqN*AEm7!>T%3 zp9mg&WRn{gGDZ#65IOiFeQ(7!8y+9IXQTEt5zVl9`z2fI=o_iIhszn8sZA5XbA~S& zWQ3o85cGTpEdc%n=J)K?aQ}xpX=$BfeEFv9!tD<-%Tfhvci8%ACovb$5+hEO$i2?6 zcjW6S?3+9UuVnr|p%MN!>SR<;WFeO!@*=7^%srGh2wX@@8@_aVd;b-p&JlGlI4S(e z*(^t;5#U2xn=6^h5CSjcnCl$G3Bv2%gCXdHar8C1qcL=iSohI@6a7!mwDP7rv6UZ* zPRO8=9@&M~VtgZRqT|ILl`#&#R*O-1D(a>0KdK(P-z8(^`RA9*AI~uyx_q%5KW5>g z22) zKi@NUizhp1ZEqcuGi|Mu7kFc0kwn{wt<`xB=DU}^APf@PZoe8oayiyF?dr=1_mp0o z4qx;5lRajv}n&?(a^vVm>7(tQvc00&*~heAd`7csCa+w;fAqW3GN6tbXD7 z`JGIQ`rsWy{M401|DusF&tNaJeq4R5_R;W4s={Y~$;QQIbjc+T_6I%ATeIyDrT??Y zHl~{!h|N9Ol`)qlc0ejWpaVx8j`B%ccK4TCoixT=YBOfy#4)DXQ|kHQRNmfL;0{=@ ztIw%T?{GsJkL{f{7i>~t^9wst6YWEOBQ;`!uS?&Gc56sSKlyV+2k!s^UYC*Ch)#bu zh3K~iVX%G|x%N}inaI;TwbZ7!`C)z9qL<_DwqEEzK^weA6SnnRB}%BhI|?lB5tr^o z<0f>%a6s?Vr-erd(mhHCS1bGPAUL81)F1z#Pz%PBPAOd z`YXZP*8L<3U6Xm8*#b$5vP`7+o_POD4xmZkP$NPd)CMyq%9R2k<2K^j9lI9bt zP@Sb79wLAGQMGZFUFVP;cHOy;B3@@MsRm}9AD7S#+}?{|az;*sHY9f;)!QG1B>4~y zMVMDqDu{rT3KK`~?GLDaX2|{hK{6khoQHeMJ-P1qo?SN_uu=uMC!LfgmK|)m7`fV1 z33>Z!ouO-0B=D(LBh{|$2ul)uxONbE{Avyn1c8Lzv0m$6MAt92x?n^17tDdEL@CwA=ZB0g{SDUWD%oJNxGS5Qevp=Lpzf zoVw;Fcr%tz?6L~n$BB}Rnrz5@>anb;O<^cawJ(&h@?c}=(L=|sxp~`4S$JB%E|%xG z_k49|J;_c+vfyJR4@1?6+5kA^mgV(W{jk_}gbmXMrJpvmQ1P*$jFM_Y=79|lKSkvU z@mPRd0aTy<@DSar_ZgpHb-DX}?VkKZ{ni_TV_gQv`iVg|1|q@6!mo3;a ztoX_DE^cBYol<|yEF@=Mxgs~0LzRAdc%{N|zUs@XkX=Nxhf4Q!c_)sVUUbbe|>9W&Fi;2 zR!f=f6Q84?=a)vIgPZ3M_kDgU-uSpmx~Vtkyy(K{?ek4LJ5KUkV2;1zNevS21>uC~ zdY;AlYw52|%nI(q1M{#aAViM@h`wqLjPBcjX3xnWmmcPtqTV|#jS4trL48S@ zG__tZPIY7gYoUCuaig=Q!91n0{Dz44z^Y<$>k6#tjSfxSP6h^6xF+sPDt^w{0t z=G8?mE4|=t$yc^876cvUS=ea^jw})T1oHk=_4_s6d#$v|H|qnSRZ_U(q$iOlaW!+t z_CHH2XfU`UF8`LIhIfon}fON5m)Ti+OV=J|F{|R<9%jr!Goie zL^|jMO2}DnTuOJx@RHQG#)8_NC$a*pG=n;aPO~yaqkk^V1tL5=jAgcZ%sTM zG{g#@+MVz<9IXjHUb#-okmk=Vc;1E4Y?T?FA|X$H*VI?-HP)DuO}_*<;P&IpFvH-b zote>Fh|(E~uFYeM%%dEKbOnY6?t`3__agxAIF@SxJC@t+tXxENx8n-i$W!H33;YJ9 zW8E9?A^D2stv`ibeq*!aX7CUh9M*2cKgNGaqR8%pLP&gaW6bW<4R}ALf&1zlD=JUk zUs=xRi`iQEuw6ITk6?=*!~2bGkJ%#O2yD_q(MU~&Eu3cSN=-HZ`^f|bkV*`gt}Zb! z3+$qJ#q*aJh@Om5vjC=StSWG?l$yXrJ+Ho$=Xt&N$r##e!fmd5S@0_6%UVtPlQpP= z8VboT+$9zeWMG+@A3h!x$;HR_^dR33+ULj7McSf-E;JS%6 za_>m-wY*TW%jz1fyFK`n%lvx`wfCrp)bpbUN$Gn~XJC5^T{%<)&L?*cS=S9K(099W zMAx5K+BDu54Yt-Cz2U`tQODIZp0l9$$=EwR>bYBq4Wj#)QaY%9Lcj0?I-U{HixL|z zi|dyhIvEV2p4|G3=dmD__X*CPVIl_-^?5>02YsGPx9_cJ5`4acS|D6VE!9D`Q%}kW zC9)p&7fj?GJKV(cPO`z~xW~()2KOMfJ!t2OmH=lnI_IU(K1(~^K7HmQ1(EGVUcID( zTI{;S*i?ZII_n?G1DxqKf(FMn5E$@@0Tkx4Lc3Y6b}sm&)b7NYJ!PD7{K2r z%dDFk>%x>)t#&ur;PGT|KvWNS-jw>C-MeUXk%b(4`x;QbT9}AyAia3(?GR(0iB(B& z$_Sz7`1zKWo_9tk{DNJ_Lx7X3<6!-PZ=I|EhrTb-ZyLU=nD%S1!b1m+$SbwCOVUo# zC%o(Y1}*QhN`DtQfUd? zi_Ig&x^1_w8bzkA;_@i5yf0RnvzHEbSI#f$OFA(BK5B_eX5Wsm=25RNu=rZ>krUyS zV42?$8_yWy)(s5t%6+d#@-vMV0sbn1&e7DkVr74oz=~xdWk#L%s=!GG@Qj7Z_11 zM7t-!1{ehC_KX#)JXYm->>dt!_>i{qZa;Rj=^7lhVv$NsM9*ea_ll>%Cb4vvbC~Np zZWF4Xkc}$FA2BX5A};5-oN>=sb1aG}=+{5TZCgu1&fNCcW|s)^WmZ)Z6C_;R`FwTNoXf`$p)o{Vg=9XyyN$*- z?sbZsYp-+73(vKw>7~tSQaQY7NbuejMzK4hH|=eE=bcZE18%-3FL#-mY_n52TtE&; zWqe+)#oPMK!ve*VODEi}KK$U3a9JF3k4ro4Bj?z`2D2`Y-p}>)Ff(qte|688)UtqN zYNA=(X9;Q)&v;ly$4Z;-QT<;qs+&wt@Jgg*ApGqfwdEKJB96Se!ygxBz4z>~F;+k- zp?;d*C(pdu!A=>0HXGv0juaHH5E)j;_+Mx68Gz_Q^7T!C`ES>)3-E5W zN*K$;1JIJ!Ld|L6}- zB(?sAo!Tn9UwTVIrRzpw4mZ`kj88U*1V{3x0~d3y=8cA~F`IPilP$qwkXIo6TI%|X z7rGe88wvRbpE-&Y(MQwZAO&d!I5}Lyw_`ZbjVA--_@_ ztJTO9mu`=7{sP-(Rc#kXO6~9-_TMJIXYbzUxAT|Fv_!oFZ#H}=@~i!(G%+Xtwd-5E zKJ+fOn7Ep=ad+DzJ-XD@g6hNddr}i%{XvTb!qnsT8BA#Q^6XDf3$a^vr!IIpVJO+w&{9Dc&-pSO|nNvV= zr0tu~hc!D2UP5l@oftW+RFtYvaQ5CV`}anrCG&4&GOcZLqX8SZ zyWV&^$l_3rSkieU-i{(kS$B(L*HU6q3M>sJgOX_KSrmf2cu$JUV~4wVTIM5KAENNh zNdLvM^3(A<#?xFrFgcoo10stzpb}Rnyq4@0?$j+wU48BB<@=+G`}d3_NdIaW%V>#2 zro(`zExT@5aw7Z|&6T$FlG#&t&7?z$@3%aNGOfxvNosx;;Qg`Y*WBj5C(PHVxkEhF zYa0_ILI)j6bE(uIBA-xsjX^Cqjecu#&ntDOs*Z>Q8obvSYQ2|2j@FM`-K!wKJ0z=< zy}!rITTCSKg-B#2&9Ht6&#rEp<4@B*YIQUEyW1X(e8|q)Qzz%Ub6ky3M?C;uw^S0! z&~$7tSzcw*`!->f@~Z7eE+1IQc}lzu#!C#7921o@HBR!gO%G~4UN^XX!TE6Meeug}KHS1&Dru-($%cTSuS)YL45dVz{hL3iWVF5nl)Us${7j>%tWcA8kVJOB9Oa4T-f{k*Hb^B zlRy5C{162Na>Vm{9UGQBZdAYfcyQcVxvgg7rJSA7ecpS7)&Fv7T;G?= z)lP)=Mv;E?;$Gd2HxOe_t+!|IT-rGxpfVQL@QQhF$cScXbK~VGzB@Ht>B@_4;cn#G z&bDAHd%L0(yJD{(VPnnw^CI4=E)GP)5s^1LKC?29>o3M?(%oA=(v8F!yRKa`2;h|@ z-eA6c*c|7Cu;U2AAkX`3%t_?R9LRfWC$TjC%KETat+eJ>MH0_GDQU(kpSgliiXRL> zMY^;p%B{S^IhYW$I%X`5x#(E$vcO$U>a?}=aPDE-c|mbzT=IAK%72QhE82?Uvrx4i zbup<(s#IDVU?MLX)6%gcM7-+kDFDfuFW@$vh+M*9YY=w`UhW#Z_Rd0kv-^Usr>LLO zy9bQEz>b|Q%;azzH{-s$F~-^6_IjG>iMX3NFGt;&1_KINHn-!unzCpzv}VfSc3rAo z9RKf08wduD`K>6ID7ti?Z%6RjgD*=1&2l;xY(I4WqF`--<}W){1R{PNanB{$r=T+L zKlwy28Q1Kzwl4FFIeRXy+M9nhK^bniy{Bz2@}{O_f0d@>Xmr84qfS$Z{u52Vn5F5< zf3N8;Wt}e}K6$>xe~=3YSaP9nwp>^`eZB-QIB)M^LZYGVC3`kR(YC5fTR&6se>|W*oW!x2=bICU(D# zyJV9prE6$)whJKRXSr|H%WuD{qQX&&aKS1JsY(rnM%WF3#5p??g+*)81NtDGOWBWX z63!0R@lDG2$ywZ|d?mp*d<7vH8_nbHwYt?Yo)`W3d8d6kWpo_yoGo2kL$XiIq%Zc= zst>5;`or$U@rNHB)#D!{Ll18j4{7`YGqvYx zCzMoYm^++`o;WA#gnZA*lN!7}`qR0r%A~t_7NqFY+1YkQZ{xOGXR9r1Nf9|!4K#a6 zq*B_!U}<~0{?2GjT-a3}j|aW?x6j=&Tzk0ip%w2KpFJ`V?94sj?<_5qgqxg@4S8f@U078hBXO8_u8|E38Y2^ z+d(g-iA2FT=tVNa`Z2#}CH))k;VlfbqR*)ZJKL2*P)EjiqZp696JOWKv>-;D_oxWG zFHFAmEUa)@NaC?;?KTI_*tI8AeSCT7lgWVY`#1##3eeG`t&WSS+Ey!8O1W{NSkU`oQrgj! zqu94T?pweX_GOuD6bt>vREax{iA(Lvlcn*K_f*DDCBE)0=bJ z!F>XjH4S4~=R%j92)3_4+Jp0@PG+iA4ZIk3Jo+Ln69nQ;)0XI{>4ydGBFAa;UyH&O z5P7$pwa+~p${bBQaxcQtJ{fge>=3G9$;26k)M=Ub8T`#}L{PN@PR`n2V8M(#bepzV z{(5VK>JF#$BtFE2beopC=Y6D(+LFaDb1IC%$(&Ar3}aj9C$G-Peg3V_w-lPHa*Njv zAE5^zLKvP^a@B?!Hj9<+Z7NzPu?_Ir9(9rHEVRYDaV5?CvG9_x! z%Zq2Oc9pe$fh|N~>gEP=9p%ZV@x1>~EB++soZpB?=Xh0-Oc39^>g>5;n>-&F@q?X$ z0-SPtmm3B>r))C1(Q@H2wDtJW!XHh~Un-lD3t=!A4Ep&twgL;ZJqRKCIq}(u&U46vm}<>_Y#Y@8S+gDbFqC>@6(q2>}?YfEQ!_p z&G?$9ESVI(zi)i>0VZer)kT4l^{EC3x*dAR~RM%^*E{EtExmv<7 zrytlrSIT}yJ(+g8>AF#-cGxkd6|-GzOd#A+X3yTutz&|5x_6g!1zVL*gmz#P1`Nzb zl^Ch7f_fX@gRHYd{!4pld2w9rVX}%7qLm*6d$!(~knC%z6inZ%FJLghk7)6-Prsvc zTPI~{-epdX%e>>84-TG5I-Wcxj-Xv&M4WF_#hUmt4<=s?o5&sA_gf3%|CNiw(#`{% zx*^3k?0&n%GHo~TsRZLC+rw_$a6M}~aXWNxdPepk<-T=&QekUPU6d8phz;s|`MSUL zLcQd^CK($g_s@h=Ijio!?Rb`$<{XT0J{dC+PB@&yPsna4o=FT!fjt*mEzQr`{4AXT$Diii$iNJWkr;$?ue+@4KAAmg8tXe`qthLLzLctfV)m01+ zCa~0PKE|5=AB}v&{$IcU)tL!@VSXUF&;<}Z6J!HGKi^8MImxysAw)m>c{ZZ2^_-Ge zq&+a$|6i%|e_~v7zPyKKu^-IhPo#SZOS;Q`FWuMmLehO5&{pPyTI#NH!@L0>KtEGC zAy9q@D>KAZpcJa*^yeSe0wQEgJs3=1*9wksBKY8O1hf+Zi+95K%D9p}aBu@FD|3XL zj2t(o0f9tTgF6rjG6bRvH|Gu#hA6G&g297A6M{b$heIQjWMtvuJLTlm;oGoyiZ2|i ztfH(ACwi;NE6T`9!1XbX?gWIqtehxd>}33!ArR3hp7ZK(%N-AhweMpbGPViW6=%2Y+t+t7Fy3fcvu2FKu~cUVec z@T?n@rf<;2I})6*co#Lei$B&=3hsn)#-Yg=ZcYn~GlqyEs=-~!WKT5&Vsgj`Zcc3i z9*=Q^I-~}7$6!3A(KxI(c!HY~nuXW|ZkPs`5$NaJ6$umHy#ZR0(Y3QzZ0$5!KNk-93>|UH#6qu)B%H2gIiHBQgAs% zxDgr;u7D46o7H4h)npan`X*M~oR%1(H#BrDPqd>e1|ct_D5DG)*TXmwh-e9J&TVKC zS=t1U%^8bv`cY-dYO*S7vhwW8bgj^UxvXZLoW=9oSq3KDm0JDT4 z0k-lZV@NCllL1FbZ^PhS$gXN|d1d*{fH#aGT5CbH2K<5bzz`^8O(iL~2ijLtReAQb ze7*H+ZB~As(1TNqr4Dy=MH5LFvgQseJ!!x(+?<>m8+6RHt#+B~f=TzlAvrZz%n$et zPtp{cwBX#;hqM1V>EPGUGlc49Ss*^@MotKix_sI1tD)D`YKW zDY!EMha>p>uyz*$!3BqrCSl1KX)y0#TG{JuMpF*Ps*0x81|H5zUb?b+emnGZj0nz3 z256kQtd56|qYKX0lR)tCB6&N0+XO^5X^a;I>#ZpSRt{@op{bZr`ESh$tFvsH;jnmj zI1z)>6e772h-60!8IA=c6N0+}^w1QNkwG}4y`d5r@ax;>$e=k*AyzAnBtRN=J!C%| zhUALDkY`i^E+ahsTs*)`kYrf*dSINeXwa%75rYBEP0bCfKYy%VRb|=Vs8VBtv@{$~ zfa5V3Cpeh^2ThWt;L!apB)A?Ca0*}&ceu3lBxC%E#sPXsW1ar?F?kZPc=D`Ku}Z$u z35;wv))|f?!wq%eoA)9${z%`U*}!6yXVw38A~ZJa#^3=4?S<&V=92GPW3L)GiRd`J zezBO%(rzRfHqQg>$H+JmJP;&rJOZ#j36e7MGIHV$V2vtDAPjXk%eaw*kQxYfO~_e| zvex=!6Ek?h4egC)mkNDtnWTn*5IyJTh%U@Rbo1GWE)+N=9X`H?!4POSwC`m1(Vkc^ zrJ(yz83KoOAR*kmC>Ww2kkyJZij!YtJh1rLqhM3(ck~>rE4QgSWgPt+aTpmi4)=Fe z=#0iY`Z*AMrR8K4K!1U-asNB|N%jGY`tPX7pGYD(gEjeg)I~-+;4lQ|Nth==RZa^a zAqv@9T4e^8O|tXvo*)v%6GL>yl3f2%PhAOM1sJjr`kQ+GAin^05JN=czNv(@TEGg0 zvoYXDV9s7dSP!7EAzZM|Gk}>@Mw$kB)zRo z4FtG{O*d#hpnt4Kr-civWU3yBa6f5S1G;ajQ$Vz%v0&cq<&=e39cMo*4RJi{!p!ah zO-ovu)p>C^P{GJR0S7?l>|*bLBe>X8h&U-$*Jl0_6Z@`AY%92XX0f;gTtaHHS|@@d zkw75BgW+NbRv#S6Gc20vr@mhNTBHqi*^xY5z^;}(LlB)Ot5$1JIAWCmBEF-U>dfBP-OyTQ51z|JuJru8jTQmG%D^uTKUYdbSc zM>g3gxG6>0RwaZqAb4Oj5NP%T)4V_Z zK?8`u8EXQn4%9Z?Fa`&#HjERic>uO(7MD6wh!9k;3%|Dd10z^yrb7P*`!H)nU}`9k zhRL>RXO2&2=9ND@&{>TDk>CjwzYtO%Oa2F21PzjjK=r~9WhQ+bLP$driGl&5j8**m+MY#p z4Fog~Qv{g)@Z$wKi*Jb-5|D0=uCu1!VzTi2x&I?oe=h}ukdsjV*D8h#XAiXJtS(!E zGPnua^FP=8l~!!w%nAGuEGhkUY*X?W(gi$#F#VA#Fhy)OqALPK|Ltt~-Qd0PzzdZ< z8_}g-P05q|D-fcy#QT&A0uhg;QbF<_k{Rkhml?67%oJtlf5b&jq`Lxex2O!NSaJ=WGO1sBLsb8 zxA!|*nnfp;r)QR^0BwCEu)gb#=ah^hcw+EC7ZO6+VBnraf;Z?Md@GRvN0Z;6R4NaC6Wvr)CLq{Kspiujw2A< zK@+S8ya_l8m{wr-!hL}27Aj_`y}+mkT*e8t3>jrW9VfBw*C2TUhvAgQhxP=Pv6&^X zjX^0A?t~?giC6~;&VoJwU7Q32wiMhGXuLp82O@j2ZQ%3)7a=trxbrYXJQ_E{R`}66 z2WA1(BQk;F=n5@KFkZ4NoC5j@(b5Mq*)9$Tcfi11fzR0w+{@{T!Fj@cST+H;1@A!e zRCh$<_ z;y;6*XErnS*o?~%mufgnD?J(r2PBIZL0zDn_!Zt+H+Gk_dIYdLM%opFb#Vpp20U0OXq>tb5u4r#yCAzW=!ATVpgchci8~CKJNd|6-Vcj^pE#P*Unh+8K zl7_(NErgu>z-j4+DheHAX`cLds|82BxEbihqG;^ zo%4Qbtw^vWkI^^%1X()l2+N#TFqkU{L9r}&FvDMG7brrIbN~0QBpKl31Na9J+g#rq zP67;uCR2!P`@|VbB$3&ZJH1# zp|*jRslG0|PO>lghgDAAGow~ch;<++28ukuRiLHd0B}P<4B{bB7>0ELhzpi0+7pC& zrkIr^14#r(VGMj`my5mU3$*_6^A|RYl_0Vu+08;|o1ndR@B3LsZ zCIA2)j)w2RV|@X}v&9ulT1{FnY}p_MeBc<&R!bczP6(_`(2ih{{rKHVTS}fNLg!-&yH@OIB;_MG41vC=`JkULWJY@+CU`c@iM znW7d<7oG%2%#x)bu0-*00D}b62@FdtP#`F1V0us22WB2k<^+Nk4g?unA(%oM7O8+Y zj6GBm21swA$UTBBomPuWGBeF_>Wq{ z?-Qh0JkW-uWn~oQriJNNEZ$s88xEC0JPsm#AO;Avss-t9K&=F10E7flayZ*73WNmU zpQ*dVe^2KubhUI$bY+0H2byQa<01WWh7SR1S>g{?I=x!iwX#;LHVXiNPwmfC_$Nsy z1IY!4pCdXrvjX^^3}+*{DtLbj8_`dy!(c2d{sAfgXr6(6Q$zv=??1sGK+!@|d;x@c3tWgx%WT&Lor7{ z?f-s)9l?Uef_Rmx(pLx|5?G~hsC4!eL!b@GI&B;lpgSDEI^;TI2iJjYb0C6w|MN4= zYV{wOYIeQSQs+I>D zk9L79YlsoBcoG?`dY0!G($@cw9AH@mGhiRG>>y2R@()|B{L6x2hV6lv782}+ekV&n zi0%du{U=e83YMlX^}VK#OolZ5QE-wdR7?2J<$@$jE*Q*~3&`Xtxlr~11{3;iPr>gK zSgeuH;DUb*Z?b^M(~s;*zypb+w0RnjAa5l9}T&9iwGa3bptxH;=_I8b6BSHvG? z$SK8Sc7y*EB1y9c%Qh_j3#!WOQO%_Bzl#Tm6bC=Rpi0W$a{zP+h$SWE-G^-<% z904JE+|LnRhK1Bck#c(ShE_PId^}G zvk)vFD{z}3Se{_$11qxqAHCbaZwc|vR3LfM#SOGhP|Ef-n@`4=XF0ps`xPLjVSAog zQC(m^v-2f^pqUDPJ5aDVCl)&ayG9B!vsuOsJ6Hg|O`7a7aFzu=)eShv03d528ac1 zg<>E-z+oNTty3@zg+_jGhlRPx)E$$=f=@;3p|A)!55J70OAbLJd^xDbj5=t#U=}= z%o9=~K+F{KkwFCdp5gvFo&Hla3BL2|WJ1HA4CaDCLW0f&#CeHWM|TojTn=nNlK{h< z96ks&&CZ`-C0|Siy}%A3@>Eb_Dt-d^8e}qnL?R- zfXfbuejivf(b6~6p5h1$-Wy9K;GqP)>8xp}i=bveC%|$b@C1FH?k@=cu}8z|_hxk{ z;0DG9cS3_@4JCCrLuvi*g>eG6&1&Us?WC_%RDsh-O)biFxX73=MR%;d8 zr?u*rpGL1`SyD;+n=yblGO%MEOprIlim54mA1jmpqh+%qXi&QLbOa4VP{{<3=^&cx z6thA%2_Yx(8g2@9CIKdO1xpjm{A7@gear7yR)&)-P5g~2CgEbTvER7q=lC`IS$5P1 z^p~|!Pvd7XLkPp6JQr~Yt*4?!z*+ly!gasP`U4F>NjcIwXrd1mFAeRwz{xmyfXuHS zj7Y~se{%gnwio<&1r7gFFaDr{@J|qC8?<#;nk`~vK$6~%2{SFs{vpDA+lzl2VThh! zk^X>VzRK|b24O%i{vcsy1z@Ka+oS^aPpvmr^=RDRy6zykAoO!Ymt!IN*4c=@1H6%e zjp#9tL9Xq$S&YAX_5N&3e{fFz?o~XqYu~P;A2RJ%)$|`=+Mo62-%6ly{gjxUatP6FaKM1o6)iV`KtU$U;bxAf)ITZK=hwPuivsX z{Y~FTuWec9v3#UW=BfT%F37Xwg4S%gU^{&hh?hNxbs&Ij{4FB=FVNv9effhE_N@jm zE3x9A0Efv2piut*9vyzxnLkL#zgcY0?AiYuAAZ)Ee<_*%7pw9&$@FJM_Mi6kLi?9I zT|B{2GA@uKM;e@OGwJW0%9FQbUtzm=j4^)GK3}j$33>|TB;!~v)XBtmXlD{|EFB^!cKR2sr!4(wrjza}jwz=YtG60!`&iJ~Sar?6QL;pt97KzrXPo+yH+Ca7K%?cu4;-fXHV z>kCmEBK8z>2qDR?Saz@hvPPshfwz~40UO-FCLXZwf$eNXuJiR__9xc<1NLStpiBRM?7ay*lIGzUN%$I@h_*IoERD*E}53g0yk~mIdIbv_zroc`)z_ z4iAJg-@!g_fRqG76i85jk_D*sfD@pp3xzaZ0OSm`P)L1tF^tH3 z+BGF@_7{Hs2|FmwAO)J4ps-9`OQErZvIPl`V6!fq@JfWQ0xP9Jl`&X|fLNzhYEf+$ zrtE z0KX5|Uz&PpE)+1-L!c~kDA$RCf&^!phY$gpkSOZ+I7XoHDI|afP-*?)K@^YDLH2qY@x+ zB*0<^`J-S7h6pC7DH5W(K448F@UcJXKxB z_g_{N@;nqFi+<2!u|*G<$K4QcKp+&=loYV43Mz_f>M`-5v4Qe9T##?L1Y9rF?|4On zYTDz8(P1P9Jjo$A9xpjxeVA=Z#n8rPmX1dDMuy%74o2SgMh;Gvjt)kSQW_A~7nk-! zO0XZ&{)KCBA`NB6Nf=aiUYGUl7f)~77WOKCtI2QK+HO^C*U(j+B*(QlwK)FNR9Hp`$$0AB}uUZ9X+Ke6Hd zg6Z}LWe25T;En^k1PlOu^abrf0UBGN*f0VdWal*DhZlAZ=oYvEeu75&ZWqb6(1Sqxx+p*& zcrqn55YES?Y%>SrQj`((GUVA6sNMk(p#Z*s4*>88I7?6xiU?37q0K=6DTxBN0+w_^ zHNZ1SIFlGE97=@!eeuu|CRoh`8-^%lLpg~^3T5D2p`@$G|6CU41V0oMPJ))BN`wtW zqHzB1JU5sSf*-ALD8fZW5-=lN(&}Hxv~JC4bX?NM*ibAn6IoO7-)bM`1$XPmQ|wQs#BX2;s|=pD+pB< zBnk!Coq|^JHZyb()z+ncf;$N1cTjy`%mfNj4P?>lm$v9&G79WI)mm)P!@yZG6pKC` z2k>TphA5PDdblEhMe2x%${g4@5{?HJ6E6xc!OP+x%u&duf_8;-;k85+l(3>SDg4Zi zhC+tlRggl)KL~6-05N6+0a{%Jy9^=-0RVjq{y@nYB?8Os8v&{fBeT)yL)!pkDMkz6 zQ-ZSPuqvtwa?0{pB_$O#tdbgl1#yJ%{D=S?7WEfdQiBm~k@-LYCqtA8#z`eWfkFsT zCLn~Ug+qg|)F=!OZCW7e#{oE6XyICtDCL3ml!?^Bcu|@U4QQVDP&03j6Q%Tmh$)HMLgB&bp_4*CG;f26c1kl}ou z^Fm=#BmkoVY5~1*#E8g8VG7-*}M2jf2fdAc%wko+mmoC{hO`a}%``;9)CNBdvKK0AGqC z#A?aGpQtid!ouHzaMa5bw!C2pYRM_VHz8bMEih)7|KbhyZWE%k)Qq72;H#9uqXOj- z_zU$JEc}9>fiSU%)MCPdL-DlFAWwbaR{+sVeF$`dI0zR&YkvGf1L9Ct1yCqp1fz+e z$a;RrNeL_dt-d;dJbEGknpt2SLDcc9;f53j>`f0wgVgy@ApSUL-r)D13%DJCqzgR@ z>o--IsbDS?AQuf$$f7qbZP8U=i>|rYqHmf3?m?e0Jp7`l#E%mJ}=iA_yTF}a;^tt&`;jMUo5MqQs(H9LP2@wD??b1SopZ&>+ zwSj})-*G~*7E4q=f*9~O)rX!4iKNYKSUVX1U76I{Q~NB`WobPde5SE7AA!;wJnb(v zETMg+SQbjONV~S+5n2!f-TIq>_WZ=n0(@Rzgh2WRe({9K-_X%Uib;wBhR{TS1qI`a zO98_}AtXr|h(I140Juk@;Z3Nb6o5@CxFom=?>9w41NomG2cCz4{5d5EmFN}*pj1J5O)Mw{suV_D=|GS6=n2&?Su?Vts5m?HJljg9e~COC7uNkU>tvC>hTA-MU*{2>RpKF z1X=VuOIvhR*rIDJw&=0*C>2>?XXn3Q42rh@2dIpT)agHJFi~wM5M=zrcKSK-NmJ+r zRt>te(6Yhb7xa7z#M%F1ucqKEQzO3rQRjv`CT&^-8cE59gA+2qXo@;D0WHNig3Hi0 zZ0Pd8==0P@0z29vP>A0|BM@yf;QvAI1w9r%qX7?~(xAuxT+AOEW-&V>wV@Pg zJAmEn|07XTi zq5S(>#|>HZwxun)8f?+k7hCkid3*_(Kp6KL!kGREVfz~`f)1955Y=`D|AM6@GLaDR zX9>eH{5?InzZwP17BFCm0LR$iFd)XDenja3ulx^+a1H|-{!Ku53op$^bKLye{9O9X4XK_~|xxp3d5pZ(n+>n}YCqvr=EXq|`{TRZ_^>d}HX zc+?J};1FVPEFSDaFbBp8;IBoX9H8%iU!~ubO{7fwf@z@u057VC10tf%1pjCBg8iwD z2+j=xz{1-0&>xfonES_r#EgF&u`W>ie=8j@0~zES2aXxgHuQ}M#)qLC;jjO`@Ni!e zShM#fq5%$E7_g?`)Dw_k3VMbW^#;nBcH_^)|7hao6^J_7Kd)U2edqsjC}SKAFERZK zE4PF_K~o3I7~fc6KqxCv7_iO~s|S5Y;|MzN2WuEm5KIy&$g8TV0gp&?STtX2OaNTL z7f~qq7bragGq8gOe*Vvb{*O7+(Q`2bQ|nrC3W};&6_uYHK^DCWSoC^&1pNMWJ(vEh zhdN}@_y4jonlg_sLG}R_{cq|;DfQ3w`lkv6*PoivxN!aG=crkhnuSH1hxzA&=XqWI zHOhujwrO`^4t}PMLbFWT;{JrlI1PA35A;JyGAlK3Mx!jj+!sKxg|}&e+4$d?Cjjvf z3Q!M2DbWkG{RNtUg$Bc*dj|&w12jHp#cUA^(1g;W3-dft=3ag}S7@IKCGZPdG^V9S zgJJN_4Qh>{<;l0trki+yzm8qU;ykVA4>A@`-xf5fKP9I2IATj*fg>CkE_Xvk5jZu(b^W;L6aZATS$a06{H7Faih!`B{-e zprga^O0CJ4U-T`uCFNQW>{qa&?Dcmh@$D7gAi~CNzD?xF(-n3%c#Mn~1zSqCG3?os zv}=W(495=S6PA9FqkB?Ix9w>C-j`4s`lxR5?fuzHkF^I+j~7+7vox@B957X|Q%d4E zrN4%!H}!V&t-gM=ZZc9V62Z+{g%ctESVxDL+M=l`E!x0x4M9ilVrNA(SQRv2g)-;3 z-s$IWq)SSpYas1awO~!+L+Hlu(LaIEHKt1{$`f}$lrSQE?)v+^LDMmM(>0OhEXwtXoG$q~#;{jK^FwKTB6~4+21Ca{dL)8ZkAaWDi!^O)M@h z=rxjUX8h88%D(izhjh`6arvv{lNGso#{pb^$=(&9w&Op@ZOba#+LZTHFY}gtcb$1o z)X(qD>_B@(q%H!{N7~XkD}$+8out8>6h3=&{Rm@_7kf$cuw z7#+#3dHQsqzyFDOv%ZIKtIOuuz((%|mmgu@wrI{wPV`=TEtV|rnQX#1)!TUQi{){l z_I+$=e$U@#nao^fpPLcx5^Xl~t8v}H_r{KQ(;mY^yT;{@i*DE7Cv|iEgE`#mS2Euj zv|lM9&V^{xCG3?w>FLk#)k1>XmDKQh5`h@2CER!@$;yxvl-k!GJNHTFhe^qLL{fm+ zzD)>(m!TNiv9(I)HY>pXDM{XNPEYX54FQ=3W}zEQ&u_5L_$a68i#0dubL%5nN}p%v@dJ%4avG>Hb%V`*5$q;&$iL| z?QmVUhm}7+eM;npDI@PrG1Q%He0HK1dzDP(>~}b#oJ@tsw4&(MGB+Au-K)`pkWZP( zs56nvO}=2K^^oI|LCr~()oI2@**kC~xkFhiOA0!oF0R(vrF>+tqaujwS(diJZEVAk z0E-SeWSIVx_gKIeRzp?3R(fBX4ZM&4wj1~z5JSbdc58a-22 zOIPbBrYBKCVv0P^*i_gU((D=~L~~ABTok{`^Q~FHPhKw5)l_EPBi^j#8195^2F)sB zyxR@rC2F$i&CVZle8Bs__(6pIx?!191&XGt*X7)Kh6}yGqLwRzl5R=wFY0gVSLhe) z7a8+F7WwIJIyU9-TGGBX#C+8N_kiL6Gd@pV&#Cl~{fm=F9C?(o-1W~KskT3Bmw9rz zV)P-k`>89?D(bj8IMeTNAx8Y=-xt|Iq7Z!n)L zpWx)Wp?X8&ioLDK{pS0{_X}>oIG!p$QU0==-D%wEu4C3IFNe*Q#!dN1bC^+xvW!S5XGKPI zvQo47`TI{3V>Z<0{SdC*sa1aJh?;?dxq?fT{djJG4$GUoO;d#=YqmkjvV-GWcD&^K zB=uTK@PwjejU0YsX!(JI2V5&mE9@#v-q$Nvek?0GQEyc1_C0x--feSD=e)JJqKyuR1sIgt@1(I=p(bZ=fH4;N_c@O(Qw=Ih(I;-u*+1g){T%vI=2$;Vs0A zQGDvo>Mswq6^`g^zWL?AFecEooxA;s!kg;lccq$xiyR8NOal1>Ylx}i+jefZNV$tX zsEsZVy!E1`zTccQvB|S9{=r01K~+KH$CEv0N0di`M>3xuzNdIts@P3|*wNHt&}%o) zsl$GFKQ{E$=`A(}HpzjP2G?QyF?(IkJU(~%cx?Hk?2*uv%uMD=Xo5Rh;&vhcolGf7&GHg%QOZK4uJ{6xRa($1EdJq2Vg{L3& zc9qoVtJQ(O2XDU|}uj<@F2e{qqb}e!> z3$qYXLvN^5jtIN~9kI^Dr%*k#R@b8o#8MtvrS1l~F&SYq`x@HFs2x zd&9|7$}PARPNmN#9-rwHP&OM8?55@eb`&46eo65;ke8|O`621 z>^e(M%NGUe#VZfRpu**~)a&I^_wCKzq+c##l~Wz~F7RzY%-z%Y^b4~$BX(ZKtl7_U zC$uX2G?SYwvRePdkfXcg;|(kq0`V>Z*Y9s{RXb2oEPemuy{gupY?Z=Khvz=>HuCoE zt3IA#;UX*S`nLXbh}s3sO>sTQH!GN=Gn|=EYhKw=y&=5YrsAW^!OAW5;_+6Y$zC^F zQ*Kts4qtYs?Y@SN<1xoCj?<3HBM)9&@_jrN(K#ZRQ1?~wLwAoy-Q*ALJJ))g=$x#& z1G@3w&AwMn>QrtoAD%k!J>2t*b@--_w;3KV{9swPtom`y!*1aRT8{QvkEGw5EW5q- z+HBFMSXoYGPN&_4w_dM{G>q#Xo@9G9xrS5ySb$?`e$;zv@FKHY$7A;SlTXjLhBU;MjCVdanPg5+ZJ*sck;P@e zl$D=#H-j_deX**xn%Zlfs2@-r5|{Q$dazfLUtD@NJIyQE)F2SUGi3(txOVYk{@J6m zcPsfO>*0yVf4pmWzv^tyt;SnxuH7Lk$a#Hn{{Hbs?DJUR zPo=N8Z2A*XTP5d$zMY?N=qUT1vnnTNj*%g6e8yivwg<%FD1TFX06Z1H9z^D;2*fuq zxJepDAfmyRhIc*)gnAwV!B5!debX3$SX*LdsOLz2_Ms?&#P_&pP^X(N>nG$u!e07OKm7HohT=;*QJwUc z^chy4Ss|HJ725E@J}I64?LKUeTJFak`UegMKjOL^o_=9Z{2nykO|`v9B|-4|)QO25 zrpTbi}y-=AE4zsaTY2sYhUvvwMBU_+1A@tI<#&m5c=E_T*Aba7-xbw}RFZe7=n zk|FRt>*aWwwKA_X*=3>}@2eSnK4TAG`qQ%qV)#PojbzVt<4Zr|Z}oQXaU0sG)eu5B z;81g98E5vT;tE$OrPX*{_FPf?VSlme222d%BNMIG2p_b^iEs-hUT?1P7QPg|9)2+_?^F|XQKNoTYB#IP(I@y*5iUtJMx z?AxdAD&Cg0|LUn~?laV(sk;Ze=A7fxvSUJ}SWD?6_0{(G8JrZC9XfiP|M;O^;-eF0 zQmplQ8-fb`Pcp=<9x*ZPa47wpxL(AoJ~89@^P||8=k-hD)5gAZ(p%TQrHe`bd@qQP ze^BOl-b_h_>zh-KpX^mL_>RXvY{b^N+?BSdxtJMx;Ba=r)klsCR<^S}FDzxu zu2QxpN+w+jO?r#`EFZ!&xZD0|%>C)F+{=X83bxu=uD)6E?DiBU*FCMGojxGptF{WO zG~Kn*q)Uov^tmCTv&h{Nm9}*|w2nPJ%ND$B{F+#F(AxAZriU3CkSX#T_42}ts~@4)H-jr?vU1GO#R1~10&9{kF>GPrKjaF~+UJ08bk zr!^-UJsHPYk*p!d+Oj7;9@=(2sCv8Lijq>dQ@5(jMP$9)wx!selyUI5j`8&5M@%la zl<%Z>VmDoJY{hEK>8Pq5ZkpDsyCZ|w#49;RO7+SF;>uY?xm z$B8+H0uv=kKHgg;TZ*ct^5y8fYBHYfW`2pZ8r`TY{COLeli!=Q4%wfHxWr6GOv&nP zxAgEGOiEZ)Ulz3CKEhCXJ+qq2qZ2cG?6ud?vHLLZYE_Ou&U)zTegqFIVoO6A9|p_F zLCB_9sUcTlD=0Y5pX)7lAm?P@%m)<|YGw5V}&ef0z`6MrTGDD)q%Z9= z3}Byu{iTE|n$I{|k3e8uq?QdRaON>I2O}!zN$QsN4O*uWkIwM%cd(HV;ks4!&vGA} z(L{CiZI@O=W*fXo+rcW{Tp?$b%*=oeAoJI0-D6YNzY-DGvOLe^TxQsYdnd@V!VO&w zTj`^blE*^pw&`MQ*=NkQv(MVmS*bfHxZkqIcAnC23b$Zgc4R}}gT!G?PMzv@!_fm7 zE$&~j{BJuXS>8<#W0pXSJ1o7 z9re#uHOVd4I=jb%H&|=M)s&EqAJLy}m`O!sV>Ev^4w9 zn^8uw=Z+jnmi4HP{P5&_Z)3B-6@LbqZyu^W41u8~6+A~vb;}rBR16LEu3I=)zJAj% zm{G0J@rWVf(<+Um*UI-H9dmYtK@$MoQ?}tj+Zo{m~?1|94 zDOc?BD3+V4x)E1a0I6IVK2h-GoG$~!goeiVqmzXkp&=oDZ*J`_RFB?p1*^qB{%Z5# zG^61sEQZZ5>Ef5w8QEB@ySB@y^MxyB|%+G@_UZNX(?B~BVQQ{zwu40 z_vx!}d~L_sXmMzsO?nc|biw@;b8`%55o@%0+^)jq5%xDKqMp9aUhcR*?WkSxwa?F- zd$%H_jYpYF_c~QLZ~Ff6a#e7b_yLUfmYc=VisNL>u;*9ywzjsSR=ANE*kk#Kw;ybb z$UAK8m$oLDobIzJr@RSHI*mP&dk6BNPdBC*XN8_OS(rAv?| zvy_xEXx95|r+3k~sBvVDp5uGq>TNdkbBuM`Y~MGm%R6#{iKG^}Gob$Pu7NLTmO9?Z z(7Y0h=x+xry3xkP-2-hrS-xItUd_B!k&=(DvdfmmS35>-y-^AEzJ3Kl4k8>j~K@ ze87AN^QPBh@AogSINtbPuh5iTE+;&S9bMaCkErNw{ra&-N>&#C>1F-%sJpUa;^NkK zi=;4^!M!GH*wCi;2d=)b`TT}c<(ztFh703XUC~})aqNdC43d>q#?nfnjk|rXJ3oJ# zOyp_0P;}wA0e<;VSHs&R|G*Nip#vo@^!s%4*o)#Lt5ZdIW~5MuN=kXeYHq7&XcWAt zjqQ5%%ErT^rx$u@aVRv2a;~nXmy=fQjojUzJ*S?WHP*dpgMuYOZ zY&y;2T&g-Z*zY)#Zp|?nN{EY(rLLVxI&^3?Xmd$PN!_!LZF)RElQlJGMw@Oh9WWJ* zm`k{J?cR+Y7a@zjeQBRz2>Xn~i!FMA4$Wr-fTdnl=JnZPcFrpd*YDOXGsqRoFxt!c z7=Qlrt^Gs%Pzl=YOU`~7!9D~1O9>t{pJ8_wg!#Q!nS53@@FJQ}GL{U%h@;aDk67%` zrYemolBR+g+hWdf8k}I_u;SKX^!8*oesQyR6X=GHE-nt9p7(QXwC`Mvevi$!bYW;9 zu5kM}N0-0+`J)vXNIq`ute#UmOyV3b<=3kk*m3S)`Q*W|PojTQbN8+%Uj?P?&<5QI+n{1+SWwTJ) zT7h@j-?~||vv!VW?0YAAoG(q}F@NJwjsH{smN=HiJ;EAOpR=~!OJQQK+_0Be`$ER; zLfWlc#&LSBnoqtlR&>1~k5pbdW_)Or$&j0obxM~{kAN^UBw$OHlk#>Mms>xo`o8ye zr1M%t?AmSnPO}6KG>&nQv?461nDXaln0*016@kiHj7#2jka`KwZZt?SYccg52q8BSiQ@XY4 zm|X71^jEV2yloBf45#Jw1J;^K;0|$jv909lAJmKB6^KXOV!ac*&OP&-)k*8y(-ZIG zMrsCCV?GFA>c8;DzKoM_u86)`9$9;oWi7q3Wn>R;|HW3`-I-2I$$p%XlTxZO!t8bU z9V)VqB-y-ONRL;qcb9q8;@`HZu!M)qHr1vz`MgQuaH77iZ{IGqBi@OhZ}xJ9(sSS% zhS^DKEW;mG>q;Om=GSD>~{jSG%{^rdpv8^|U4iSmVXU4}z4=xjM zr^}okDA^O&v6AksrKufkVGdi-B5CR^{*E6A2l`F`!&+k!XOs!yMmSwrrnTee2i)X8Z@md>ndTwI)k=kb+H z3d?Km3?Pf&N*zz?y_b)TVr;WXviIEPUJ}KnG+pa*1o>S+O{mPY$?Vn&_NQUhg#8B( zRt2^fuaem4?CktHrZ$z`&%Qwrakw~HMCkbrYWR)Y9RIGTt4<##jsQr$xfVPh78J`PDTH8`5UnYFI zP^qA!b9moA-tvkHHS#DbOLL6X;vl-HJj9A+P5rKqj`c1#{nJyLUU7dw5b0w)StC6e zZ@(+08+}|eQ+Kz1)22Bd-7WnlE`ZYsjoAhT6Od#_n8VDKm{t1 zzUmUCzi=hD$w>2Tju_p}|K`2_?LBg;s^q7SE4qeVs{%M}v?lmW_6Qv*FW*t0Fd6k` zw~C)~fkfR|xiJ2NheOc-8EX9bOi3?q*JQ_O2n)>*1k> z!O5=2gD1+$3d-MwKrL~#_SRF4>US$$w+c2t@fkKJPYSCh&}T4m`+Bc^A6ciMkdwJ4 ze%sftb{fyu^pA~23$G3=pJ**tK`U?<`qY?~Za67eQCGUHcWB$^XAE|Bb~bfmt#Ulp!>fAQ%- zPmf^4!C2`%kw^1Q+OWc_@)-wBno1C{5;yt=vzC8|ML&q#{hCdPTyO_BeNboia~2;T z-@TyT_xm8Jnb)__Cy#RvXOfq@YIQ`fwvYDdYTAy<8W|qWAG-=#K*sZG?s1EQ_KtkG-Qacc z^5r+5$=PDt!L_k_3hn0t+t*}dWa!7{lrj1QN*r1K=JKHi&LaAIEPE3=wluY*ZPyfk zG9b;`=-&IdU1zQ?^0sg+w(I_<$u|=rQDL0)&8`DBsR(VZd-t;$Dk_(?#OS81@GEV= zvUxr}VA|qMzlMK`xdBI?K;PV+%a+zj;TxTC-2=hwtRbi@mimA78s; z^|+0hg|`Tk;s=z6ELjY3x}=qg6RBI#t_M?eI7J8b`o%~HP_i?f_Q{kg^pMgGTX~XU zgBicT+hhqk^}C4xOZ6R@X3=WcP2jh7*nrX;a^h%o)4zhl{mY5L9G zKAJM$v&a&z)&@~)@3q&R_BS>(QWjXhU zPRW82evgMeJ$E%e)is^4DyU=|UCqJ#`t|D+_UCIxpOsu@dW%lI#W6Ld`sJC3^70wG z5`H~?whHzm??%%!AMIOjF;yVz5s3?U@F22SBwwxdvusevTLe z3zco!Pp%4IAl}+scskCFPiG1R4VK?dy#Mx9CowZq<#fQ2^UE#QoO_BZ`bOf+`;wi{ z#IweWx92zU2qyH3`or7`X@Ubj!|)EUg>7cpk-k{gz;t?$Enwap+*=u5P& zckOel#3RCD`Q8CITy|lh=DK%nVaoo>1(=k_gX4Si^H)84>U&K{bF)`IWYIg8_8F$I z&nQ@I(NAR2d`9Xuu>a=KtJ7V>v(9B*Km4PkqaTM~eqp?6lUz|zk-|!-1pbaC#~Eg@ z&)D!w2^BP-fpP?^DJst+4MsD?lC2S?4AufACm7ITtqRFSih7rMrWuD;^jQiD3^v}n z&Qkx4$j~%26vUB|B*yBKWwMVnl<}i^+j-WjVI8-dwmbNo)5BfWyl~VgsY+Y5J8F}+ zv`b~P5BA=+s}5yI*7`@bc7a!ens86AgTC%`RPx%F4^{0KLb^9>`SISn-E_3l^?b_1 zhYx#GM#Q(p7|hjXzhJMJ_L*R62}%1R-lAkM!*otDB|;~xHBDkxP^M+|xcK3dKX#4G zZn?Mp&JYLly%fV&qu5KH;f$|kd*3I`inrWJVPt!7RiuWUSrFG=@#O9OfTQ z=sI64W8q373XnoewD|WJ8PuCcHg%ekU6|Ax z0afX5a$Rm}uHoY3=CiGHj9KB<5ObXM{tC+jvntM!8_XVT-7hvQg6b1| zHN~8z^;JOH`E(wS%F&}oQ#=UuPNjiHO)ewJYU8=MB9Z)_Lm#+Ttd}Tt*(y2SaZw1H zFCyVEf*TUd{ubF()~m_vwo~__zAkD*ld<*bbhTs=b(_Pzxq$+)ts8@aGt0Sr`*_dY z)-z$BV(56E!mzegVGN-W^PxAL-z#rynw62Btht7nnOR`7WXWIi8P zRz=)Dd}mxq#+C6*eYPssgQGXx*wF_I)m92}4i85L>6nVQ+)r*}W;MmCvL0TOK0VG~ z)1S=10)oK%$2^H19)g2yMQ@t7FE7;Ie26&M*7@+Ep^FQD#AU&(+f5xE++cps?v4j@ zO^%ql`s&&j*6!}BpFVw>2r5*lm0*U6z!bVg3{Pze^^|6Ss_zzjDh#ssf+=s z5;Q4Qj{fxaj#r%H<0zD_f$Wt8lnAFx%&OC8%20#xSR?%&w{HUVXKcS8k-1CfQ61Jd z@fbsB<2u}K;_tr>m{&v2`9*d$*|AG^nx9%C&W7AwVKXCJ z??sq?_W0VZ$!n8Z%3)8iAA9$UZNFcjGTx?f=-a@B12^t(W#Hi%+lV{LKb>$R4kgXux zNJo=Hb*@aK$L_SYnuEDH?aI*M48PbaFqit$2UR5EB_XVB_+DbC`$*BL8N@=8{s$2A9+)$<5Zt!fH_28qIo z)Ll2Z4~r#y>!X|cq7{TxzM(VSnMHoRU81pgd~_5$F)<;e7L{g@xop$asIPUgrde$4 zB+1c@Wz?lNynlOrR@PgAYc0J_vL5@6eHSyk%3>O=DiqdJz58R&<*c6f8&Cas&40aj z_WP%`HQ2L=2zTlBQ<1Zbxc($1B(MDqpN!%d0cBkWjW3szwU8Vu1$a^1Nv493MPCan zx)mb=e*e0j!KmY54q5b^;>8yIv?R@4Pc zrO{#Xv2z%9a<`AD-si?i`ftXidkYBH@)JgCGBrl7__wk|j=Zc-=*JT2Bwd$@3l6PA z$ufyrnLE2y6tX;j#vsezpTFtBVA6MbQ#sU-UPtm124e<8SClA^d*Rr*shPxWSc6an zAvH#c6oXOF6D{1_R=s%fBJoS7iKCO#rm_Azr|u1MqHKQ5<V-O+xhA?Z3nNsnZZL%ARv&}8hD9wiaSnzICV#0(ZlU&*H8C$qpc5$1y_ifz0xn<;&r&VxDCWx>NtuPV zFCR;1T{XR*G~{|xgM&dfdmyQD%gIW|0LR11@0n*)G+#Z*w6w!Kks+I~jRJLZ*mtZp zyQ()01Vv-x<8Bv&cy_Lo_3LX)$AP#cHP63Q#Rqcbb&v3|^SR3)(S&b^e$*86*A zrjz!!tb1^PZd}Z4M}Dh$aX={DSNge(8TyET8{cmtKCOS8r77H*$kcK-`;~Sso0!=? zzD>L7rkVP`-8dBZZ2SF`*l8KwZv#ES$ZX-3RMxKbW``J>E%x!<7I0{@sVXwr;?O=< zbjqe%h8(!Z2+?^|GJq~LTWJvAqR^CA_F2;Vj0B{8$5-j=&$d$(7F(d-z zKucMFz!b>chJSzt=cGaeU?OG_0DhYYp?N`vOry*RK@lK%9bjHYNf1%~Ag>qZ+ZVJD zt;)264k4Hu2+Erx2z3-pj>-x^>;?!60M`ib2S~u_!VudStP+L_bq4r>et-cW&PWFU z{~ZyC2H6HA0)!HaCJ|s!!jjZN&0`QkV8uu%-wyzWM}wq)2uU0rg$JN#{&-1@q{qfs zaUY4-NqMi6@Y?R#Sp{ecdDJ`pm+8~7q1hD5c^kb0O>>nh9ijge zgnrBhmjIB7Ap~McjF+UZWCTtpk(fx5(n<7_j3y<?`Gg+9>OZ36=tU$jV9mECVWsDiBI(B!VR&79Ryk4}uql zB?dhN)da2|8lcY;VVTeKPm=&j8YL$+&##AssCNPopC{(;OQi|~D+NeU_@G_^^hgA! zNC3S-;b{Iog$qgfUwNd;4CYaCAvb!m?w-<#;)$T4J*7R+-k$IWDsQO7L`VgxFSdVK z(T$!`oBu&A7f5rF$mc7+bXDbORfSN!kek69iNtJxUPz>2T!e2pIKXp3N7J7NYlkfQ z8DP=>yeU)cq%H^-_qfb&%7haY+hg?4?w+>guK2P#j=$-V z!#R0iQ|2ph6eu{JGA1~Xl9&#%m0_p^!)RxKCxMTG_-tF6&r>j;&VS`|&q|n2PYRzO zm-b&^*Ca?26JN~do|UxR!6~pA2#KT_qv#lL*l;kMF%4`C1W!p^V8SsJ=zQ1`*#nS5 z&~0!ika`bbZww&lQE*Z&1cU=l2qpqlEsDvVrwxOXf+s*WHuL}lZbLJ(Aj2*WBac=B zgyANJ3xILfVW@t5B)|q21)W(Gr~z~t9MS-D0$pB+k-Je8zPwRXd;UoP1pM<+3gj*A z9)P8R5tJ$9F|^B305ldpM-~uYbP*^W9x4$&!~j-Eh?i)8%E8E5C~#mi1_PN607e2i z2w*6}eE||B3V_=IhDn5|IDmLd!TE;niyF>fhO`?ZM(_)XjtT>XKv42Fevte@L4Ydd zhKB^m^#-_15}x1@2|eI(K#n)`ozgupz#aMe!Dm)P0%T_3l^|k3+bD;gLuW<+_#lwJ z4pQi8MWZ5v@&4e@WQttDuPEh9LJUxx%{tSIUn-=p!eEf;=KrLkxz>Fo0g8z|#S^6=Dz)nE+XA>Mw!N zXfzhFO1rp#Fc3JvYyY#rs6Y9Oyl5qX6P;;oL8%K(M)P(YVqF3w0kKXKwjUm#&q8?S zsD;e`m5HCsgT6u|OcN!{_)op`2Hj(Uu0#STd&!?Y7}7}CU{Ju_sm%#RNsx|F8VX#b zJ_Q0T_;e45AkCCW15-jhyksK))Rm^;#6zUOJ;A-dXdK}Unj*caCXum4$>pw_pg&C^xHkGA-}NScClZ`IZE?i&$$tZC}1au5Ku17 z^g;a>I#D7D!iI(=1FJ101khhWtvrG~;YT2?r`oKacRb-x46Y~Y7s`Kq7A6B!7li^~ zN>BidqW%yfJ#Tb@)uqOF)VseD{#iP$_hJ7UWG#4TflAItAW-2y*_dbK&qcw!qfjvS z@IQ;ixZvB*m|PYLw?$E+5O?z-JqSvnZZ$suf{v!5Xs)yt3f4Iy@LoXr|4xe+FaUo1 z8%3t}J(?Lu#{&2^ydsmitr=P1(0DNoCDbh)S;bJeB!8oO9Mt9!`b~rOPNx(j$byJR|h} zwaYMad4Pm)UFMuS3%bnD?0pdO303`pgFEj; zeyr!mg2XkeG5Wemd+CBzg=S-fDvf*3)~mGNvcA6c$KV5d%)W>H+VTC4MR%iRT%KHf zu*W?+^oSWldu-4w<2Ba)A2+rVuReG@sjR9n?kK>#%Kx#K$McpuirfHW;8X8S!6D3$ z@2AwrQ)Pos#~NRsJQ^&Z)+qioR*hi@=lu|iMdmP!W@|BfeKsyLG?^`LG+U4jZ`evR zBk~)j$hSjesN-)*@| zo_m9QKNevAKJqdnmH_A>K_=(m&IKk%R=?^(_D)&^)E(dG{kq^f@ra^Qz%hr2`o)32Bx)r0j&-Cm!geNHJoLHXzAQuNUIyr`m>}I zCLl>|Mb1k~8et3Z1bEA|SQLsT^A@B>5_xh!2kzra3(>5U)nEX7$y-@9pfdhj$dcQPBU}ghoQ^tbYLE5wzP+AXhG{{Qh2nlGF zy;>5=CK0BUx_}mdpE+j@FS-E@$dF!0>-N&LHp8@17SIB7><1X&SQOB@=D(0uX75q~ z!10at;wX^M8ii+52h{_&^c`EaBLP+6k) zZh`BSyr5o?jBJ362H~&+@IrY(9Pz$clGaw3R?-4mkc=3CjA9{L*ZdaJnn5xw#a9wc zYwH49Ads2*4#N-u86nIU(mKV?u!LqF4}~PfnL973pLT8r(oF9#ilmltF3C|c%+Z!# zIGO<*?Sg8DFk8q`uRRmYBE+V>BZ60no)WCFB0vs-CRZE8QK|4eN45ytq}qNWM4^OU zjnyk21R9J?7a8eUk%+bL>!Is(3=Aw#8?0Kx@@Kipc%;Bw#x3B|R=?Ya4p1lg@XpO) ziz$>TH8umZ{@kOv+F>rSzi>$c^yqE5)mXV4C{$$DvVeR61pNNBu5`Iv9T1fxO~0ig zpvD>k#(yS8jwmoA6AK>}Lj>~+@WdSkfUHLP`paU`igIW$W<>|aL+2U)1>6gQ*#-Dl z&~zOq62fDb)e8i{qB_co5D$*o@Wm*hu_#GbIWUg3433B&TjKRcH0D+8wZqnjWbrcCtCc&VCG7Hy^$Pf&nG&wwM@zwA!jZIou zwAwu6o+^!y?EiHvH%N!RgBDxDCV=d9V1pBX(INVz+JRn3(~Unt`Ut%sTAd7Rh!bEi z0=@q-Aj$JcgJ|Wj|CSaQkeL4Xw*wN|7{UQQIaVD2e*+YGJeZqRL@T2tjqx}_l&=&g z($bemlC>h>00ulB9L(Ve4M?ym017?^8jvWUFMhQ>Y3=mCW??26eKL@X zeSmq49Wv4thr{?AMVXO~<3Gf_EO5ge=- zX{Ht~7Zl)P7hoDeHYP=qgF~=t&gQ{khOTPndPVsGoB>wJJ%SKJG;<}yS<736hq~!27?91dNJS?bTsT1mCv6nyw#i-9HWuTe zte~jm9BvYdHI0d}at&3nHg$D0h?90wGcYIFMn*g1Tnya(V*Ct)9n53gk%nf zl?YoycNLo$7dij9U^N%Zcy~8dCp)?OikL_H;f$PWZ|G{tB7~RnHdqy z&3s*Akyw`q8>LV)lNiHze-kUq2onpurJ1jygWe|jSVehvcYS+8tX+(`l~J^9G~RcU zlfPUnPR`0PJOF3r4vyJ&L`JAMnqn+s^@Ckw$f@yA{J_`IUwgH{1wCUWlRJPoFxy=_#+YmNRTE+K<)~Jt>8ayFi}s3 zKp}!ah_Dj0g(P@`OW+FSI{1S?fP25b=0H^a|G)n%gPEBby6Nfvr@gBWj;gxikBB2; zsG_5-p!lXD1k8rr&G&-sBq70wkQh)RvCx<7Cah$4!@gY-+B#Y~eqgIb?Nn;%3`$G= z>W8SU6s*)b$aHY5AXAKAXbUoqqD52$W&8V`yZiR;F8ds2`llHJO!D6E{qDKvo^$Sf z=j=Ip3jY04IUPB28P6j7@BNV@M;=9<T-d%a$#l;!CdCv13PS?cK{#&uv+o8Vnh!?_eC4w|om@XiFg< zo|s>>w6r`mJUo0cZV-`HaJpYUH&N5PC&M@TqQKLqEJaOX0 z;m*#^4I4LZoZ~hh{N15Lhe{6|IB+h%4<0;tCg(8otgrsn^&Jxo3G3gVUt}0tPr*lP zDPuwJa3d_bi!a|LzPvow3%^s+xI28j{j50;9)vX_%0GaD4Xu3V?_-SSu3N>&=uPgi zuMQs5WTdJ==I};C=Nfz0A=^1B`!w`o4!tz z&vrQ|3yk*JGZrA!P)7?BO7)|KgE#T#JX#>~%9q@bOD`evhHVaVr_uiRv)}$L5qM}Z z{+l_-IEct1zqHE@dAm*IcLyEhYmN40iAn#>AeSvKj{N9uH{_L)pyX|IkQW;5P3!vQ z;E$Zgo>?4u_P^Ya_dHI{!?g}_7mhn0uJL6!AIHWvdxUc^M;ed5?uNX-p2#~MbC9ny z+P{5l)L$~lL%DLsW<4us@1l{#1Eun=+YBJzYiq&Hg2q>8jDUWu;o;DE?<>wq&wRit zzN|KVgDgMW@32&Qwgz}|IP~%T3T1TCmC-6;6xSGaHojIf0($iz8I40!Kq)G$R$vup zR62=_HoW36Qu_HI@PyHkrxZ$?JEPl$(K3zEwT-WPM?fDBk&$PC&WKpW8EsFH(Yv=h zjFes<0-i7`#aiULtGm%vMn4ut0~(`+jc-gH0X;4!qwzS7$;#+vU=?Sy@?kRaW)m~i zdMF2;Fgm(kF`Bo^mC;XxQA}fWUE`Y*M?gzAlhLXYoskW!;*9nO$Y{rNj*OJHZw8() z>ie@|wAP)`9l|K8G3sjEJ7EM?q@Rq=eNAVy!IjaTC&*~{3Wt$e*?!;&qr535zShdRekY7NG)8b3*N+#6fdlO6k8|Dfi&#JZg{uqOO-AddI*jDFm@e%43);uR zg`KWYp1#kO(eH)PRe6jq03+lnfYC<92eCOAUAK9RaToj{KQqQn{r(`6t>;eB z)R)Yj(fJW4+tZer?6JUlRT8KSFxzI289mcV zpqQbsB&0Urtq=HW)UoTyo#D2`!{w&G+HC7ds54xz7bo}uWS7jEGk?tJ=J{41IxzQE z)!_`czOK5bs@HFMPo}=4-sgAS6aT*saYyrwhWP^-1bTpZP$~nVU?|m9rpH^0WCWyh zO*O9`V8<||D6-v@^jI>{_!LRY6=s>A44a%*uY8Z4WFOmB=uia|{LOj1z!(-S<16PFl_vAoJ-^+KsUz3~t#t&)Ak zt`5eMpd*)^05474jv+VRirOfqu~mw70>A%;v7j8%HwduusozPdmq-bB^uDuxGf zhOkOx<@BN;N(nCtz35*7u}2eeN|f=eCiWjkBMKd{&-eR5q5A&1vBDHQv)V>PowTCymVuyle3o7r_dceX8 z4I#%FVpkZt)=nwRt4Yz^86+S6dLLQ1H5EK;Q-pgV&TD{Ch5&g720AxGaAZXlu^{P zh@BK>1#UIlxr@a{=?HjQUp`BY2mT3mzEUyudwf0*Ut^=b7EBp8)ahp4M$ABR5OdPD zkV?yCr3eNB&CVElP`P2_mtgPE7NW|u%ff^@#0G7cBMTpTLE{Nb)Ci$*JEtAX4S5^N z>C4iECfF!L5)?_wXQ2Ta|I+g$tfe3Y6NY-1xQ$n|u|Xk8?a8o|8w;6IbHlI>sN_N% z0F7gmLEcn7hkM%2XhX=6I3<{opSR9~WDg(SsZ<3j>EazXNe2XV>kaoMQR%BHVmav0 z5XzIJY$6(qdLW9Jc+Dha3%!WPvFiCWdAKw$hU35!of%UWACaE7I#5}w>()HPBkahI zp0ZMtLIaW=lZ045Mns!DEz24)YIMV^-z5c0WxXQVYy7HA4B`a*ZVFkbw^zYG1s ztZ_VoeECl07ru)_l6&A6_+8)^ZtlWH68nV@wT&kH!mM%P7jRbkG;)vvel9Ux2I*i) z&3wfYF-(2&bUX=tqXwdADHM*Nd9(y7HC3MOa6*QU9FWEKpfvz1&MIxZe5Y1lTw4RL zk)r{OtJD4!&b6jWK$GgfN~JK-X%1$Y)2%xl0(4kmnA->}VI&y=mt{%h3I)w3#*|Ja zH30k-H5HY)55|O~UB4fC=keCFI^O3CKnJy@J1-L|W+D;lVJsd&YkKB_Fem;51ERvh zh+?6lF|-7x1F?9*>V~SIrF{Vpr57+CUJrItupm{w0LW>!E8HsQE|Sg7^l1mW28T zdXos;U^uMh%0xyGR>xOl3>jl@TG4)PDby1Ytil=$E(s$@cc=!1Y7|ait$tjAkYI9R z3R$bjfe+5N3KUl>{3ympB}ZL9R*9Grc(#sq)HUb=Pb>X`SbV7!Xa8zp(t=>Tao)_d z(u=$^dx~HPK{|pes~}Q`JxZG+sD72lS7-YCc$v-oD_!kkQTPSfttkydNn}R8YK>`Y zStfHTvh{}OLVDsTK~zIwwJ*I>P? z4@u{nmsYj4HeuqZ#?S-oCa`l-_K5q)Y*DOiI_6z7*NoSC>*{i+jfS2k+GPW9ff)L? z3l061NY(A!`rP@3aSl+9-S1XFu;)pl47WNc`bp{7`ca2}s!;BGzzt>PBSi6L>!Wp>(t2m?m)5&N@ zHbq!}2LMKWe^QKY`Hd^1-NH!!)I`3OD8XBaEo8LruR5dkTV398ly&V9tjU_ZvsgI2 zUneQq#G|Bk0;~AwfP~R)OgZvaquT;*ICsbBo>V9!{^rW)6=9@*NJ3UK!N_y3KDsf$ zItfN<-Bv==h0$Szc^sG5ozbu`xfh@?o7(;N%!78{olu5k^PxHj#|F+!>(_ z7j$x>#we?kVB~v7XB0X)MrxHj1RWPfN76cZt2-mScLJk}HAdNW3r5Xn>x}L`IY!FD OeFQroj7mov#{U2a?Y^)8 literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/http/proxy.pcap b/testing/btest/Traces/http/proxy.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e0e7adf3d4f7a723ea90ad9663d04bc7df9580e3 GIT binary patch literal 18521 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 KuRq(3output && btest-diff output + +file_extraction.bro + + +global mime_to_ext: table[string] of string = { + ["application/x-dosexec"] = "exe", + ["text/plain"] = "txt", + ["image/jpeg"] = "jpg", + ["image/png"] = "png", + ["text/html"] = "html", +}; + +event file_new(f: fa_file) + { + if ( f$source != "HTTP" ) + return; + + if ( ! f?$mime_type ) + return; + + if ( f$mime_type !in mime_to_ext ) + return; + + local fname = fmt("%s-%s.%s", f$source, f$id, mime_to_ext[f$mime_type]); + print fmt("Extracting file %s", fname); + Files::add_analyzer(f, Files::ANALYZER_EXTRACT, [$extract_filename=fname]); + } diff --git a/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_01_bro.btest b/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_01_bro.btest new file mode 100644 index 0000000000..4e10859d98 --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_01_bro.btest @@ -0,0 +1,9 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +http_proxy_01.bro + +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code == 200 ) + print fmt("A local server is acting as an open proxy: %s", c$id$resp_h); + } diff --git a/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_02_bro.btest b/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_02_bro.btest new file mode 100644 index 0000000000..01e3822001 --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_02_bro.btest @@ -0,0 +1,30 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +http_proxy_02.bro + + +module HTTP; + +export { + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; +} + +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( /^[hH][tT][tT][pP]:/ in c$http$uri && + c$http$status_code in HTTP::success_status_codes ) + print fmt("A local server is acting as an open proxy: %s", c$id$resp_h); + } diff --git a/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_03_bro.btest b/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_03_bro.btest new file mode 100644 index 0000000000..5139fa8c49 --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_03_bro.btest @@ -0,0 +1,35 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +http_proxy_03.bro + + +@load base/utils/site + +redef Site::local_nets += { 192.168.0.0/16 }; + +module HTTP; + +export { + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; +} + +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( Site::is_local_addr(c$id$resp_h) && + /^[hH][tT][tT][pP]:/ in c$http$uri && + c$http$status_code in HTTP::success_status_codes ) + print fmt("A local server is acting as an open proxy: %s", c$id$resp_h); + } diff --git a/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_04_bro.btest b/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_04_bro.btest new file mode 100644 index 0000000000..a8ca8e19b2 --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_httpmonitor_http_proxy_04_bro.btest @@ -0,0 +1,44 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +http_proxy_04.bro + +@load base/utils/site +@load base/frameworks/notice + +redef Site::local_nets += { 192.168.0.0/16 }; + +module HTTP; + +export { + + redef enum Notice::Type += { + Open_Proxy + }; + + global success_status_codes: set[count] = { + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 304 + }; +} + +event http_reply(c: connection, version: string, code: count, reason: string) + { + if ( Site::is_local_addr(c$id$resp_h) && + /^[hH][tT][tT][pP]:/ in c$http$uri && + c$http$status_code in HTTP::success_status_codes ) + NOTICE([$note=HTTP::Open_Proxy, + $msg=fmt("A local server is acting as an open proxy: %s", + c$id$resp_h), + $conn=c, + $identifier=cat(c$id$resp_h), + $suppress_for=1day]); + } diff --git a/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro.btest b/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro.btest new file mode 100644 index 0000000000..ef537b6c53 --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro.btest @@ -0,0 +1,39 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +mimestats.bro + +module MimeMetrics; + +export { + + redef enum Log::ID += { LOG }; + + type Info: record { + ## Timestamp when the log line was finished and written. + ts: time &log; + ## Time interval that the log line covers. + ts_delta: interval &log; + ## The mime type + mtype: string &log; + ## The number of unique local hosts that fetched this mime type + uniq_hosts: count &log; + ## The number of hits to the mime type + hits: count &log; + ## The total number of bytes received by this mime type + bytes: count &log; + }; + + ## The frequency of logging the stats collected by this script. + const break_interval = 5mins &redef; +} +event HTTP::log_http(rec: HTTP::Info) + { + if ( Site::is_local_addr(rec$id$orig_h) && rec?$resp_mime_types ) + { + local mime_type = rec$resp_mime_types[0]; + SumStats::observe("mime.bytes", [$str=mime_type], + [$num=rec$response_body_len]); + SumStats::observe("mime.hits", [$str=mime_type], + [$str=cat(rec$id$orig_h)]); + } + } diff --git a/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@2.btest b/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@2.btest new file mode 100644 index 0000000000..027eade4dc --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@2.btest @@ -0,0 +1,8 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +mimestats.bro + + local r1: SumStats::Reducer = [$stream="mime.bytes", + $apply=set(SumStats::SUM)]; + local r2: SumStats::Reducer = [$stream="mime.hits", + $apply=set(SumStats::UNIQUE)]; diff --git a/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@3.btest b/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@3.btest new file mode 100644 index 0000000000..e410c6ebb9 --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@3.btest @@ -0,0 +1,18 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +mimestats.bro + + SumStats::create([$name="mime-metrics", + $epoch=break_interval, + $reducers=set(r1, r2), + $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) = + { + local l: Info; + l$ts = network_time(); + l$ts_delta = break_interval; + l$mtype = key$str; + l$bytes = double_to_count(floor(result["mime.bytes"]$sum)); + l$hits = result["mime.hits"]$num; + l$uniq_hosts = result["mime.hits"]$unique; + Log::write(MimeMetrics::LOG, l); + }]); diff --git a/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@4.btest b/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@4.btest new file mode 100644 index 0000000000..0e97a0b14e --- /dev/null +++ b/testing/btest/doc/sphinx/include-doc_mimestats_mimestats_bro@4.btest @@ -0,0 +1,68 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +mimestats.bro + +@load base/utils/site +@load base/frameworks/sumstats + +redef Site::local_nets += { 10.0.0.0/8 }; + +module MimeMetrics; + +export { + + redef enum Log::ID += { LOG }; + + type Info: record { + ## Timestamp when the log line was finished and written. + ts: time &log; + ## Time interval that the log line covers. + ts_delta: interval &log; + ## The mime type + mtype: string &log; + ## The number of unique local hosts that fetched this mime type + uniq_hosts: count &log; + ## The number of hits to the mime type + hits: count &log; + ## The total number of bytes received by this mime type + bytes: count &log; + }; + + ## The frequency of logging the stats collected by this script. + const break_interval = 5mins &redef; +} + +event bro_init() &priority=3 + { + Log::create_stream(MimeMetrics::LOG, [$columns=Info]); + local r1: SumStats::Reducer = [$stream="mime.bytes", + $apply=set(SumStats::SUM)]; + local r2: SumStats::Reducer = [$stream="mime.hits", + $apply=set(SumStats::UNIQUE)]; + SumStats::create([$name="mime-metrics", + $epoch=break_interval, + $reducers=set(r1, r2), + $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) = + { + local l: Info; + l$ts = network_time(); + l$ts_delta = break_interval; + l$mtype = key$str; + l$bytes = double_to_count(floor(result["mime.bytes"]$sum)); + l$hits = result["mime.hits"]$num; + l$uniq_hosts = result["mime.hits"]$unique; + Log::write(MimeMetrics::LOG, l); + }]); + } + +event HTTP::log_http(rec: HTTP::Info) + { + if ( Site::is_local_addr(rec$id$orig_h) && rec?$resp_mime_types ) + { + local mime_type = rec$resp_mime_types[0]; + SumStats::observe("mime.bytes", [$str=mime_type], + [$num=rec$response_body_len]); + SumStats::observe("mime.hits", [$str=mime_type], + [$str=cat(rec$id$orig_h)]); + } + } diff --git a/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro.btest b/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro.btest new file mode 100644 index 0000000000..59d57223d9 --- /dev/null +++ b/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro.btest @@ -0,0 +1,21 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +detect-bruteforcing.bro + +module FTP; + +export { + redef enum Notice::Type += { + ## Indicates a host bruteforcing FTP logins by watching for too + ## many rejected usernames or failed passwords. + Bruteforcing + }; + + ## How many rejected usernames or passwords are required before being + ## considered to be bruteforcing. + const bruteforce_threshold: double = 20 &redef; + + ## The time period in which the threshold needs to be crossed before + ## being reset. + const bruteforce_measurement_interval = 15mins &redef; +} diff --git a/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@2.btest b/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@2.btest new file mode 100644 index 0000000000..648fe8a559 --- /dev/null +++ b/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@2.btest @@ -0,0 +1,13 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +detect-bruteforcing.bro + +event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) + { + local cmd = c$ftp$cmdarg$cmd; + if ( cmd == "USER" || cmd == "PASS" ) + { + if ( FTP::parse_ftp_reply_code(code)$x == 5 ) + SumStats::observe("ftp.failed_auth", [$host=c$id$orig_h], [$str=cat(c$id$resp_h)]); + } + } diff --git a/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@3.btest b/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@3.btest new file mode 100644 index 0000000000..f81c9f50ba --- /dev/null +++ b/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@3.btest @@ -0,0 +1,27 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +detect-bruteforcing.bro + +event bro_init() + { + local r1: SumStats::Reducer = [$stream="ftp.failed_auth", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(bruteforce_threshold+2)]; + SumStats::create([$name="ftp-detect-bruteforcing", + $epoch=bruteforce_measurement_interval, + $reducers=set(r1), + $threshold_val(key: SumStats::Key, result: SumStats::Result) = + { + return result["ftp.failed_auth"]$num+0.0; + }, + $threshold=bruteforce_threshold, + $threshold_crossed(key: SumStats::Key, result: SumStats::Result) = + { + local r = result["ftp.failed_auth"]; + local dur = duration_to_mins_secs(r$end-r$begin); + local plural = r$unique>1 ? "s" : ""; + local message = fmt("%s had %d failed logins on %d FTP server%s in %s", key$host, r$num, r$unique, plural, dur); + NOTICE([$note=FTP::Bruteforcing, + $src=key$host, + $msg=message, + $identifier=cat(key$host)]); + }]); + } diff --git a/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@4.btest b/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@4.btest new file mode 100644 index 0000000000..bb7b0fd078 --- /dev/null +++ b/testing/btest/doc/sphinx/include-scripts_policy_protocols_ftp_detect-bruteforcing_bro@4.btest @@ -0,0 +1,64 @@ +# @TEST-EXEC: cat %INPUT >output && btest-diff output + +detect-bruteforcing.bro + +##! FTP brute-forcing detector, triggering when too many rejected usernames or +##! failed passwords have occurred from a single address. + +@load base/protocols/ftp +@load base/frameworks/sumstats + +@load base/utils/time + +module FTP; + +export { + redef enum Notice::Type += { + ## Indicates a host bruteforcing FTP logins by watching for too + ## many rejected usernames or failed passwords. + Bruteforcing + }; + + ## How many rejected usernames or passwords are required before being + ## considered to be bruteforcing. + const bruteforce_threshold: double = 20 &redef; + + ## The time period in which the threshold needs to be crossed before + ## being reset. + const bruteforce_measurement_interval = 15mins &redef; +} + + +event bro_init() + { + local r1: SumStats::Reducer = [$stream="ftp.failed_auth", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(bruteforce_threshold+2)]; + SumStats::create([$name="ftp-detect-bruteforcing", + $epoch=bruteforce_measurement_interval, + $reducers=set(r1), + $threshold_val(key: SumStats::Key, result: SumStats::Result) = + { + return result["ftp.failed_auth"]$num+0.0; + }, + $threshold=bruteforce_threshold, + $threshold_crossed(key: SumStats::Key, result: SumStats::Result) = + { + local r = result["ftp.failed_auth"]; + local dur = duration_to_mins_secs(r$end-r$begin); + local plural = r$unique>1 ? "s" : ""; + local message = fmt("%s had %d failed logins on %d FTP server%s in %s", key$host, r$num, r$unique, plural, dur); + NOTICE([$note=FTP::Bruteforcing, + $src=key$host, + $msg=message, + $identifier=cat(key$host)]); + }]); + } + +event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) + { + local cmd = c$ftp$cmdarg$cmd; + if ( cmd == "USER" || cmd == "PASS" ) + { + if ( FTP::parse_ftp_reply_code(code)$x == 5 ) + SumStats::observe("ftp.failed_auth", [$host=c$id$orig_h], [$str=cat(c$id$resp_h)]); + } + } diff --git a/testing/btest/doc/sphinx/mimestats.btest b/testing/btest/doc/sphinx/mimestats.btest new file mode 100644 index 0000000000..06e47ea888 --- /dev/null +++ b/testing/btest/doc/sphinx/mimestats.btest @@ -0,0 +1,2 @@ +@TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/http/bro.org.pcap ${DOC_ROOT}/mimestats/mimestats.bro +@TEST-EXEC: btest-rst-include mime_metrics.log From c4b440b3e725e2205e7c302a8d81a9e6cf1cbfea Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Wed, 22 Jan 2014 12:14:03 -0800 Subject: [PATCH 035/254] Updating submodule(s). [nomail] --- aux/broctl | 2 +- aux/btest | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aux/broctl b/aux/broctl index c1b8087220..c4b5fb7336 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit c1b808722048443f909fea26898ea0e308e28c95 +Subproject commit c4b5fb7336f2b598cf69777a7ec91b4aa16cacd1 diff --git a/aux/btest b/aux/btest index 26c3136d56..23ff11bf0e 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit 26c3136d56493017bc33c5a2f22ae393d585c2d9 +Subproject commit 23ff11bf0edbad2c6f1acbeb3f9a029ff4b61785 From 18bd20fe29635907b7571742d7eba1486fcbdd5a Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 23 Jan 2014 14:16:52 -0800 Subject: [PATCH 036/254] Fixing initialization context in anonymous functions. When an anonymoys function was defined inside an initialization context, that context transfered over to the function body and could lead to spurious error messages. --- CHANGES | 5 ++++ VERSION | 2 +- src/parse.y | 23 +++++++++++++++---- .../language.init-in-anon-function/http.log | 23 +++++++++++++++++++ .../btest/language/init-in-anon-function.bro | 16 +++++++++++++ 5 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 testing/btest/Baseline/language.init-in-anon-function/http.log create mode 100644 testing/btest/language/init-in-anon-function.bro diff --git a/CHANGES b/CHANGES index a064e25456..2cbebd0255 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,9 @@ +2.2-117 | 2014-01-23 14:18:19 -0800 + + * Fixing initialization context in anonymous functions. (Robin + Sommer) + 2.2-115 | 2014-01-22 12:11:18 -0800 * Add unit tests for new Bro Manual docs. (Jon Siwek) diff --git a/VERSION b/VERSION index fcc0720534..33ad1f2a99 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2-115 +2.2-117 diff --git a/src/parse.y b/src/parse.y index 941a268c0b..5835c57143 100644 --- a/src/parse.y +++ b/src/parse.y @@ -117,6 +117,7 @@ int in_init = 0; int in_record = 0; bool resolving_global_ID = false; bool defining_global_ID = false; +std::vector saved_in_init; ID* func_id = 0; EnumType *cur_enum_type = 0; @@ -452,7 +453,7 @@ expr: } | '$' TOK_ID func_params '=' - { + { func_id = current_scope()->GenerateTemporary("anonymous-function"); func_id->SetInferReturnType(true); begin_func(func_id, @@ -462,7 +463,7 @@ expr: $3); } func_body - { + { $$ = new FieldAssignExpr($2, new ConstExpr(func_id->ID_Val())); } @@ -1113,12 +1114,24 @@ func_hdr: ; func_body: - opt_attr '{' stmt_list '}' + opt_attr '{' + { + saved_in_init.push_back(in_init); + in_init = 0; + } + + stmt_list + { + in_init = saved_in_init.back(); + saved_in_init.pop_back(); + } + + '}' { if ( optimize ) - $3 = $3->Simplify(); + $4 = $4->Simplify(); - end_func($3, $1); + end_func($4, $1); } ; diff --git a/testing/btest/Baseline/language.init-in-anon-function/http.log b/testing/btest/Baseline/language.init-in-anon-function/http.log new file mode 100644 index 0000000000..9dfebce2ea --- /dev/null +++ b/testing/btest/Baseline/language.init-in-anon-function/http.log @@ -0,0 +1,23 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path http +#open 2014-01-23-22-15-45 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth method host uri referrer user_agent request_body_len response_body_len status_code status_msg info_code info_msg filename tags username password proxied orig_fuids orig_mime_types resp_fuids resp_mime_types +#types time string addr port addr port count string string string string string count count count string count string string table[enum] string string table[string] vector[string] vector[string] vector[string] vector[string] +1300475168.784020 CRJuHdVW0XPVINV8a 141.142.0.0 48649 208.80.152.118 80 1 GET bits.wikimedia.org /skins-1.5/monobook/main.css http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475168.916018 CJ3xTn1c4Zw9TmAE05 141.142.0.0 49997 208.80.152.3 80 1 GET upload.wikimedia.org /wikipedia/commons/6/63/Wikipedia-logo.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475168.916183 C7XEbhP654jzLoe3a 141.142.0.0 49996 208.80.152.3 80 1 GET upload.wikimedia.org /wikipedia/commons/thumb/b/bb/Wikipedia_wordmark.svg/174px-Wikipedia_wordmark.svg.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475168.918358 C3SfNE4BWaU4aSuwkc 141.142.0.0 49998 208.80.152.3 80 1 GET upload.wikimedia.org /wikipedia/commons/b/bd/Bookshelf-40x201_6.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475168.952307 CyAhVIzHqb7t7kv28 141.142.0.0 50000 208.80.152.3 80 1 GET upload.wikimedia.org /wikipedia/commons/thumb/8/8a/Wikinews-logo.png/35px-Wikinews-logo.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475168.952296 CzA03V1VcgagLjnO92 141.142.0.0 49999 208.80.152.3 80 1 GET upload.wikimedia.org /wikipedia/commons/4/4a/Wiktionary-logo-en-35px.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475168.954820 CkDsfG2YIeWJmXWNWj 141.142.0.0 50001 208.80.152.3 80 1 GET upload.wikimedia.org /wikipedia/commons/thumb/f/fa/Wikiquote-logo.svg/35px-Wikiquote-logo.svg.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475168.962687 Cn78a440HlxuyZKs6f 141.142.0.0 35642 208.80.152.2 80 1 GET meta.wikimedia.org /images/wikimedia-button.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475168.975934 CJ3xTn1c4Zw9TmAE05 141.142.0.0 49997 208.80.152.3 80 2 GET upload.wikimedia.org /wikipedia/commons/thumb/f/fa/Wikibooks-logo.svg/35px-Wikibooks-logo.svg.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475168.976436 C7XEbhP654jzLoe3a 141.142.0.0 49996 208.80.152.3 80 2 GET upload.wikimedia.org /wikipedia/commons/thumb/d/df/Wikispecies-logo.svg/35px-Wikispecies-logo.svg.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475168.979264 C3SfNE4BWaU4aSuwkc 141.142.0.0 49998 208.80.152.3 80 2 GET upload.wikimedia.org /wikipedia/commons/thumb/4/4c/Wikisource-logo.svg/35px-Wikisource-logo.svg.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475169.014619 CyAhVIzHqb7t7kv28 141.142.0.0 50000 208.80.152.3 80 2 GET upload.wikimedia.org /wikipedia/commons/thumb/4/4a/Commons-logo.svg/35px-Commons-logo.svg.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475169.014593 CzA03V1VcgagLjnO92 141.142.0.0 49999 208.80.152.3 80 2 GET upload.wikimedia.org /wikipedia/commons/thumb/9/91/Wikiversity-logo.svg/35px-Wikiversity-logo.svg.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +1300475169.014927 CkDsfG2YIeWJmXWNWj 141.142.0.0 50001 208.80.152.3 80 2 GET upload.wikimedia.org /wikipedia/commons/thumb/7/75/Wikimedia_Community_Logo.svg/35px-Wikimedia_Community_Logo.svg.png http://www.wikipedia.org/ Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15 0 0 304 Not Modified - - - (empty) - - - - - - - +#close 2014-01-23-22-15-45 diff --git a/testing/btest/language/init-in-anon-function.bro b/testing/btest/language/init-in-anon-function.bro new file mode 100644 index 0000000000..45f5f09f09 --- /dev/null +++ b/testing/btest/language/init-in-anon-function.bro @@ -0,0 +1,16 @@ +# @TEST-EXEC: bro -r ${TRACES}/wikipedia.trace %INPUT >out +# @TEST-EXEC: btest-diff http.log + +module Foo; + +event bro_init() { + + Log::remove_default_filter(HTTP::LOG); + + local filter: Log::Filter = [$name = "http", + $pred = function(rec: HTTP::Info): bool { + rec$id$orig_h = remask_addr(rec$id$orig_h, 0.0.0.0, 112); + return T; + }]; + Log::add_filter(HTTP::LOG, filter); +} From 392d1cb759e0f53f9a841709835657a6ecbee460 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 23 Jan 2014 17:05:48 -0800 Subject: [PATCH 037/254] Updating submodule(s). [nomail] --- aux/broccoli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/broccoli b/aux/broccoli index e02ccc0a27..52ba12128e 160000 --- a/aux/broccoli +++ b/aux/broccoli @@ -1 +1 @@ -Subproject commit e02ccc0a27e64b147f01e4c7deb5b897864d59d5 +Subproject commit 52ba12128e0673a09cbc7a68b8485f5d19030633 From 5b3573394edbcf6c8926e84c21d84c13faa412e7 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 24 Jan 2014 15:51:58 -0600 Subject: [PATCH 038/254] Improve TCP FIN retransmission handling. In the case multiple FIN packets are seen from a TCP endpoint (e.g. when one is retransmitted), only the first counted towards a byte in the sequence space. This could cause a subsequent FIN packet to induce an incorrect wrap around in the sequence numbers (e.g. the retransmitted FIN packet now is one sequence number behind the the first) and misleadingly large connection sizes. The change is to always treat a FIN packet as counting one byte in to the sequence space. --- src/analyzer/protocol/tcp/TCP.cc | 11 ++++------- .../btest/Baseline/core.tcp.fin-retransmit/out | 2 ++ testing/btest/Traces/tcp/fin_retransmission.pcap | Bin 0 -> 434 bytes testing/btest/core/tcp/fin-retransmit.bro | 8 ++++++++ 4 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 testing/btest/Baseline/core.tcp.fin-retransmit/out create mode 100644 testing/btest/Traces/tcp/fin_retransmission.pcap create mode 100644 testing/btest/core/tcp/fin-retransmit.bro diff --git a/src/analyzer/protocol/tcp/TCP.cc b/src/analyzer/protocol/tcp/TCP.cc index aefc5a1808..57c4ebef18 100644 --- a/src/analyzer/protocol/tcp/TCP.cc +++ b/src/analyzer/protocol/tcp/TCP.cc @@ -373,14 +373,11 @@ void TCP_Analyzer::ProcessSYN(const IP_Hdr* ip, const struct tcphdr* tp, void TCP_Analyzer::ProcessFIN(double t, TCP_Endpoint* endpoint, int& seq_len, uint32 base_seq) { - if ( endpoint->FIN_cnt == 0 ) - { - ++seq_len; // FIN consumes a byte of sequence space - ++endpoint->FIN_cnt; // remember that we've seen a FIN - } + ++seq_len; // FIN consumes a byte of sequence space. + ++endpoint->FIN_cnt; // remember that we've seen a FIN - else if ( t < endpoint->last_time + tcp_storm_interarrival_thresh && - ++endpoint->FIN_cnt == tcp_storm_thresh ) + if ( t < endpoint->last_time + tcp_storm_interarrival_thresh && + endpoint->FIN_cnt == tcp_storm_thresh ) Weird("FIN_storm"); // Remember the relative seq in FIN_seq. diff --git a/testing/btest/Baseline/core.tcp.fin-retransmit/out b/testing/btest/Baseline/core.tcp.fin-retransmit/out new file mode 100644 index 0000000000..8afb8222c9 --- /dev/null +++ b/testing/btest/Baseline/core.tcp.fin-retransmit/out @@ -0,0 +1,2 @@ +[size=0, state=5, num_pkts=3, num_bytes_ip=156, flow_label=0] +[size=0, state=6, num_pkts=2, num_bytes_ip=92, flow_label=0] diff --git a/testing/btest/Traces/tcp/fin_retransmission.pcap b/testing/btest/Traces/tcp/fin_retransmission.pcap new file mode 100644 index 0000000000000000000000000000000000000000..1e17844af55bcf6ccb65c637d5f4f9f3f1173321 GIT binary patch literal 434 zcmca|c+)~A1{MYw`2U}Qff2|lH#!zHv5}R*56A}LBZdF0Vh=^guQHL?!@=Onz~Ery z<-p*;#w*OlC|4@D{Gim6=W*o?i&Wthj-opy7^s$ko-S+Td;crAns*h0-5Mz$i-j-G#!L7 z+^EsH59G$J+tA$zH1%eHpaX;bGLXwa0A$v$i+pgiFkGjR&jxaxMjo2$ZuY$_{20KZ Mz_~;MViE%b0C*yJumAu6 literal 0 HcmV?d00001 diff --git a/testing/btest/core/tcp/fin-retransmit.bro b/testing/btest/core/tcp/fin-retransmit.bro new file mode 100644 index 0000000000..42bf062f5a --- /dev/null +++ b/testing/btest/core/tcp/fin-retransmit.bro @@ -0,0 +1,8 @@ +# @TEST-EXEC: bro -b -r $TRACES/tcp/fin_retransmission.pcap %INPUT >out +# @TEST-EXEC: btest-diff out + +event connection_state_remove(c: connection) + { + print c$orig; + print c$resp; + } From 9b12967d40b2624cec097732fd8e0b0efaae4612 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 24 Jan 2014 16:21:02 -0600 Subject: [PATCH 039/254] Improve gap reporting in TCP connections that never see data. The previous behavior was to accomodate SYN/FIN/RST-filtered traces by not reporting missing data (via the content_gap event) for such connections. The new behavior always reports gaps for connections that are established and terminate normally, but sequence numbers indicate that all data packets of the connection were missed. The behavior can be reverted by redef'ing "detect_filtered_trace". --- scripts/base/init-bare.bro | 6 ++++++ src/analyzer/protocol/tcp/TCP_Reassembler.cc | 2 +- src/const.bif | 1 + .../Baseline/core.tcp.miss-end-data/conn.log | 10 ++++++++++ .../btest/Baseline/core.tcp.miss-end-data/out | 1 + testing/btest/Traces/tcp/miss_end_data.pcap | Bin 0 -> 1216 bytes testing/btest/core/tcp/miss-end-data.bro | 10 ++++++++++ 7 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 testing/btest/Baseline/core.tcp.miss-end-data/conn.log create mode 100644 testing/btest/Baseline/core.tcp.miss-end-data/out create mode 100644 testing/btest/Traces/tcp/miss_end_data.pcap create mode 100644 testing/btest/core/tcp/miss-end-data.bro diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 8d4899b785..ce8d68d289 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2849,6 +2849,12 @@ global load_sample_freq = 20 &redef; ## .. bro:see:: gap_report const gap_report_freq = 1.0 sec &redef; +## Whether to attempt to automatically detect SYN/FIN/RST-filtered trace +## and not report missing segments for such connections. +## If this is enabled, then missing data at the end of connections may not +## be reported via :bro:see:`content_gap`. +const detect_filtered_trace = F &redef; + ## Whether we want :bro:see:`content_gap` and :bro:see:`gap_report` for partial ## connections. A connection is partial if it is missing a full handshake. Note ## that gap reports for partial connections might not be reliable. diff --git a/src/analyzer/protocol/tcp/TCP_Reassembler.cc b/src/analyzer/protocol/tcp/TCP_Reassembler.cc index a1e20dc0e6..49292a04a5 100644 --- a/src/analyzer/protocol/tcp/TCP_Reassembler.cc +++ b/src/analyzer/protocol/tcp/TCP_Reassembler.cc @@ -178,7 +178,7 @@ void TCP_Reassembler::Undelivered(int up_to_seq) // to this method and only if this condition is not true). reporter->InternalError("Calling Undelivered for data that has already been delivered (or has already been marked as undelivered"); - if ( last_reassem_seq == 1 && + if ( BifConst::detect_filtered_trace && last_reassem_seq == 1 && (endpoint->FIN_cnt > 0 || endpoint->RST_cnt > 0 || peer->FIN_cnt > 0 || peer->RST_cnt > 0) ) { diff --git a/src/const.bif b/src/const.bif index fd0419c7d9..0ba168ca85 100644 --- a/src/const.bif +++ b/src/const.bif @@ -5,6 +5,7 @@ const ignore_keep_alive_rexmit: bool; const skip_http_data: bool; const use_conn_size_analyzer: bool; +const detect_filtered_trace: bool; const report_gaps_for_partial: bool; const exit_only_after_terminate: bool; diff --git a/testing/btest/Baseline/core.tcp.miss-end-data/conn.log b/testing/btest/Baseline/core.tcp.miss-end-data/conn.log new file mode 100644 index 0000000000..723e5becc3 --- /dev/null +++ b/testing/btest/Baseline/core.tcp.miss-end-data/conn.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open 2014-01-24-22-19-38 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string bool count string count count count count table[string] +1331764471.664131 CXWv6p3arKYeMETxOg 192.168.122.230 60648 77.238.160.184 80 tcp http 10.048360 538 2902 SF - 2902 ShADafF 5 750 4 172 (empty) +#close 2014-01-24-22-19-38 diff --git a/testing/btest/Baseline/core.tcp.miss-end-data/out b/testing/btest/Baseline/core.tcp.miss-end-data/out new file mode 100644 index 0000000000..cd5881035f --- /dev/null +++ b/testing/btest/Baseline/core.tcp.miss-end-data/out @@ -0,0 +1 @@ +content_gap, [orig_h=192.168.122.230, orig_p=60648/tcp, resp_h=77.238.160.184, resp_p=80/tcp], F, 1, 2902 diff --git a/testing/btest/Traces/tcp/miss_end_data.pcap b/testing/btest/Traces/tcp/miss_end_data.pcap new file mode 100644 index 0000000000000000000000000000000000000000..ae5aecbaac78f2ebd7243f373f1142c690fbda0e GIT binary patch literal 1216 zcmaLXOH30%7y#huf<_xl025+-gpHA=KzFxG>24pXDMemE+6HR$V4}ZyVoczQ6gf zy8{Z_!SOvTEfORMyaa$~Klk3()<*bz?F1Ho@=ejRJl7Ke$N=vA)n%+<6%=-Nrq^D? zk-ERw-Sg$n#-WHbq+Z10dfX2!@PIWmD_$$Ab{Ii z6(TD_tW>W3SGkhupPK|=Vys9q+z=aM<{e3Trii*`F&rO_#fGDaOfJIH3r2~YEEWq4 zOS1w0q;A2kf?)}I6T(oV9Lw#; zP~YuDk5`RpqAn>~DM^+ZiV;R@WmT}@@%U(2FfE9}oSMs1@pvpjv0=xSskrO#VJ`|k z;2+gB4T?DSBw2ybpafN^A!ioK(1d1^EZeq`WEiv^{3o#tUa40U6n6GO8ZHbk*zp8k z9paoya6TOkT4_;Ek+S-zmbP@KY@|q47ZKfX)0B3P+852%>*zx)9y4rd}DH3o-+9LOr`27)X5ujsB|G^ d(^G^WP33f64*w5cx14ANo#-;o%hEmoe*w*=ZlnMJ literal 0 HcmV?d00001 diff --git a/testing/btest/core/tcp/miss-end-data.bro b/testing/btest/core/tcp/miss-end-data.bro new file mode 100644 index 0000000000..6cee7577d9 --- /dev/null +++ b/testing/btest/core/tcp/miss-end-data.bro @@ -0,0 +1,10 @@ +# @TEST-EXEC: bro -r $TRACES/tcp/miss_end_data.pcap %INPUT >out +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff conn.log + +redef report_gaps_for_partial = T; + +event content_gap(c: connection, is_orig: bool, seq: count, length: count) + { + print "content_gap", c$id, is_orig, seq, length; + } From 6d46144c3b1453d429848a699767215b61302024 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 24 Jan 2014 16:32:55 -0600 Subject: [PATCH 040/254] Improve TCP connection size reporting for half-open connections. If TCP endpoint A and B are synchronized at some point, but A closes/aborts/crashes and B goes on without knowledge of it and then A tries to re-synchronize, Bro could end up seeing something like (sequence numbers made up): A: SYN 100 B: ACK 500 A: RST 500 The final sequence number of A, in this case, is not useful in the context of determining the number of data bytes sent by A, so Bro now reports that as 0 (where before it could often be misleadingly large). --- src/analyzer/protocol/tcp/TCP_Endpoint.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/analyzer/protocol/tcp/TCP_Endpoint.cc b/src/analyzer/protocol/tcp/TCP_Endpoint.cc index d596234021..ad642a46e3 100644 --- a/src/analyzer/protocol/tcp/TCP_Endpoint.cc +++ b/src/analyzer/protocol/tcp/TCP_Endpoint.cc @@ -161,6 +161,13 @@ void TCP_Endpoint::SetState(EndpointState new_state) bro_int_t TCP_Endpoint::Size() const { + if ( prev_state == TCP_ENDPOINT_SYN_SENT && state == TCP_ENDPOINT_RESET && + peer->state == TCP_ENDPOINT_INACTIVE && ! NoDataAcked() ) + // This looks like a half-open connection was discovered and aborted. + // Sequence numbers could be misleading if used in context of data size + // and there was never a chance for this endpoint to send data anyway. + return 0; + bro_int_t size; uint64 last_seq_64 = (uint64(last_seq_high) << 32) | last_seq; From e09763e0613ea6ea8134d11957e419e3061b5db0 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 24 Jan 2014 16:47:00 -0600 Subject: [PATCH 041/254] Fix file_over_new_connection event to trigger when entire file is missed. If a file is nothing but gaps (e.g. due to missing/dropped packets), Bro can sometimes detect a file is supposed to have been present and never saw any of its content, but failed to raise file_over_new_connection events for it. This was mostly apparent because the tx_hosts/rx_hosts fields in files.log would not be populated in such cases (but are now with this change). --- src/file_analysis/File.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/file_analysis/File.cc b/src/file_analysis/File.cc index 55b28763c8..deda0f9e93 100644 --- a/src/file_analysis/File.cc +++ b/src/file_analysis/File.cc @@ -103,7 +103,6 @@ File::~File() DBG_LOG(DBG_FILE_ANALYSIS, "Destroying File object %s", id.c_str()); Unref(val); - // Queue may not be empty in the case where only content gaps were seen. while ( ! fonc_queue.empty() ) { delete_vals(fonc_queue.front().second); @@ -460,20 +459,27 @@ void File::FileEvent(EventHandlerPtr h) FileEvent(h, vl); } +static void flush_file_event_queue(queue >& q) + { + while ( ! q.empty() ) + { + pair p = q.front(); + mgr.QueueEvent(p.first, p.second); + q.pop(); + } + } + void File::FileEvent(EventHandlerPtr h, val_list* vl) { + if ( h == file_state_remove ) + flush_file_event_queue(fonc_queue); + mgr.QueueEvent(h, vl); if ( h == file_new ) { did_file_new_event = true; - - while ( ! fonc_queue.empty() ) - { - pair p = fonc_queue.front(); - mgr.QueueEvent(p.first, p.second); - fonc_queue.pop(); - } + flush_file_event_queue(fonc_queue); } if ( h == file_new || h == file_timeout || h == file_extraction_limit ) From 56acd99d15e2e64182a685afa84efe7741213b8c Mon Sep 17 00:00:00 2001 From: Vlad Grigorescu Date: Fri, 24 Jan 2014 21:00:55 -0500 Subject: [PATCH 042/254] Fix misidentification of SOCKS traffic. Traffic that had a certain bytestring would get incorrectly identified as SOCKS. This seemed to happen a lot with DCE/RPC traffic. --- src/analyzer/protocol/socks/socks-analyzer.pac | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/analyzer/protocol/socks/socks-analyzer.pac b/src/analyzer/protocol/socks/socks-analyzer.pac index 885542fc2a..b7cbaaceac 100644 --- a/src/analyzer/protocol/socks/socks-analyzer.pac +++ b/src/analyzer/protocol/socks/socks-analyzer.pac @@ -64,6 +64,12 @@ refine connection SOCKS_Conn += { bro_analyzer()->ProtocolViolation(fmt("invalid value in reserved field: %d", ${request.reserved})); return false; } + if ( ( ${request.command} == 0 ) || ( ${request.command} > 3 ) ) + { + bro_analyzer()->ProtocolViolation(fmt("invalid value in reserved field: %d", ${request.reserved})); + bro_analyzer()->SetSkip(true); + return false; + } RecordVal* sa = new RecordVal(socks_address); @@ -105,7 +111,7 @@ refine connection SOCKS_Conn += { function socks5_reply(reply: SOCKS5_Reply): bool %{ RecordVal* sa = new RecordVal(socks_address); - + // This is dumb and there must be a better way (checking for presence of a field)... switch ( ${reply.bound.addr_type} ) { From 6d73b8c57e5bd74a0e7b880d2e547cd6da3649b9 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Mon, 27 Jan 2014 10:22:06 -0800 Subject: [PATCH 043/254] Fix x509_extension event. The event now really returns the extension. If openssl supports printing it, it is converted into the openssl ascii output. The output does not always look pretty because it can contain newlines. New event syntax: event x509_extension(c: connection, is_orig: bool, cert:X509, extension: X509_extension_info) Example output for extension: [name=X509v3 Extended Key Usage, short_name=extendedKeyUsage, oid=2.5.29.37, critical=F, value=TLS Web Server Authentication, TLS Web Client Authentication] [name=X509v3 Certificate Policies, short_name=certificatePolicies, oid=2.5.29.32, critical=F, value=Policy: 1.3.6.1.4.1.6449.1.2.1.3.4^J CPS: https://secure.comodo.com/CPS^J] --- scripts/base/init-bare.bro | 12 ++++ src/NetVar.cc | 2 + src/NetVar.h | 1 + src/analyzer/protocol/ssl/events.bif | 6 +- src/analyzer/protocol/ssl/ssl-analyzer.pac | 61 +++++++++++++------ .../.stdout | 20 ++++++ .../base/protocols/ssl/x509_extensions.test | 7 +++ 7 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.protocols.ssl.x509_extensions/.stdout create mode 100644 testing/btest/scripts/base/protocols/ssl/x509_extensions.test diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 8d4899b785..7f80e63f54 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2432,6 +2432,18 @@ type X509: record { not_valid_after: time; ##< Timestamp after when certificate is not valid. }; +## An X509 extension. +## +## +## .. bro:see:: x509_extension +type X509_extension_info: record { + name: string; ##< long name of extension. oid if name not known + short_name: string &optional; ##< short name of extension if known. + oid: string; ##< oid of extension + critical: bool; ##< true if extension is critical + value: string; ##< extension content parsed to string for known extensions. Raw data otherwise. +}; + ## HTTP session statistics. ## ## .. bro:see:: http_stats diff --git a/src/NetVar.cc b/src/NetVar.cc index 79652112f3..05a4e16b47 100644 --- a/src/NetVar.cc +++ b/src/NetVar.cc @@ -48,6 +48,7 @@ int tcp_max_above_hole_without_any_acks; int tcp_excessive_data_without_further_acks; RecordType* x509_type; +RecordType* x509_extension_type; RecordType* socks_address; @@ -356,6 +357,7 @@ void init_net_var() opt_internal_int("tcp_excessive_data_without_further_acks"); x509_type = internal_type("X509")->AsRecordType(); + x509_extension_type = internal_type("X509_extension_info")->AsRecordType(); socks_address = internal_type("SOCKS::Address")->AsRecordType(); diff --git a/src/NetVar.h b/src/NetVar.h index 12949c0e55..8ef6571313 100644 --- a/src/NetVar.h +++ b/src/NetVar.h @@ -51,6 +51,7 @@ extern int tcp_max_above_hole_without_any_acks; extern int tcp_excessive_data_without_further_acks; extern RecordType* x509_type; +extern RecordType* x509_extension_type; extern RecordType* socks_address; diff --git a/src/analyzer/protocol/ssl/events.bif b/src/analyzer/protocol/ssl/events.bif index 01abb87745..7319d2ce3e 100644 --- a/src/analyzer/protocol/ssl/events.bif +++ b/src/analyzer/protocol/ssl/events.bif @@ -178,11 +178,13 @@ event x509_certificate%(c: connection, is_orig: bool, cert: X509, chain_idx: cou ## ## is_orig: True if event is raised for originator side of the connection. ## -## data: The raw data associated with the extension. +## cert: The parsed certificate. +## +## extension: The parsed extension. ## ## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension ## ssl_server_hello x509_certificate x509_error x509_verify -event x509_extension%(c: connection, is_orig: bool, data: string%); +event x509_extension%(c: connection, is_orig: bool, cert: X509, extension: X509_extension_info%); ## Generated when errors occur during parsing an X509 certificate. ## diff --git a/src/analyzer/protocol/ssl/ssl-analyzer.pac b/src/analyzer/protocol/ssl/ssl-analyzer.pac index 18d3812742..0156671ce8 100644 --- a/src/analyzer/protocol/ssl/ssl-analyzer.pac +++ b/src/analyzer/protocol/ssl/ssl-analyzer.pac @@ -9,6 +9,7 @@ #include "util.h" #include +#include #include %} @@ -298,25 +299,51 @@ refine connection SSL_Conn += { int num_ext = X509_get_ext_count(pTemp); for ( int k = 0; k < num_ext; ++k ) { - unsigned char *pBuffer = 0; - int length = 0; + char name[256]; + char oid[256]; + + memset(name, 0, 256); + memset(oid, 0, 256); X509_EXTENSION* ex = X509_get_ext(pTemp, k); - if (ex) - { - ASN1_STRING *pString = X509_EXTENSION_get_data(ex); - length = ASN1_STRING_to_UTF8(&pBuffer, pString); - //i2t_ASN1_OBJECT(&pBuffer, length, obj) - // printf("extension length: %d\n", length); - // -1 indicates an error. - if ( length >= 0 ) - { - StringVal* value = new StringVal(length, (char*)pBuffer); - BifEvent::generate_x509_extension(bro_analyzer(), - bro_analyzer()->Conn(), ${rec.is_orig}, value); - } - OPENSSL_free(pBuffer); - } + + if ( !ex ) + continue; + + ASN1_OBJECT* ext_asn = X509_EXTENSION_get_object(ex); + const char* short_name = OBJ_nid2sn(OBJ_obj2nid(ext_asn)); + + OBJ_obj2txt(name, 255, ext_asn, 0); + OBJ_obj2txt(oid, 255, ext_asn, 1); + + int critical = 0; + if ( X509_EXTENSION_get_critical(ex) != 0 ) + critical = 1; + + BIO *bio = BIO_new(BIO_s_mem()); + if(!X509V3_EXT_print(bio, ex, 0, 0)) + M_ASN1_OCTET_STRING_print(bio,ex->value); + + BIO_flush(bio); + int length = BIO_pending(bio); + // use OPENSSL_malloc here. Using new or anything else can lead + // to interesting, hard to debug segfaults. + char *buffer = (char*) OPENSSL_malloc(length); + BIO_read(bio, buffer, length); + StringVal* ext_val = new StringVal(length, buffer); + BIO_free_all(bio); + OPENSSL_free(buffer); + + RecordVal* pX509Ext = new RecordVal(x509_extension_type); + pX509Ext->Assign(0, new StringVal(name)); + if ( short_name and strlen(short_name) > 0 ) + pX509Ext->Assign(1, new StringVal(short_name)); + pX509Ext->Assign(2, new StringVal(oid)); + pX509Ext->Assign(3, new Val(critical, TYPE_BOOL)); + pX509Ext->Assign(4, ext_val); + + BifEvent::generate_x509_extension(bro_analyzer(), + bro_analyzer()->Conn(), ${rec.is_orig}, pX509Cert->Ref(), pX509Ext); } } X509_free(pTemp); diff --git a/testing/btest/Baseline/scripts.base.protocols.ssl.x509_extensions/.stdout b/testing/btest/Baseline/scripts.base.protocols.ssl.x509_extensions/.stdout new file mode 100644 index 0000000000..3f9c8661bf --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ssl.x509_extensions/.stdout @@ -0,0 +1,20 @@ +[name=X509v3 Authority Key Identifier, short_name=authorityKeyIdentifier, oid=2.5.29.35, critical=F, value=keyid:3F:D5:B5:D0:D6:44:79:50:4A:17:A3:9B:8C:4A:DC:B8:B0:22:64:6B^J] +[name=X509v3 Subject Key Identifier, short_name=subjectKeyIdentifier, oid=2.5.29.14, critical=F, value=A2:76:09:20:A8:40:FD:A1:AC:C8:E9:35:B9:11:A6:61:FF:8C:FF:A3] +[name=X509v3 Key Usage, short_name=keyUsage, oid=2.5.29.15, critical=T, value=Digital Signature, Key Encipherment] +[name=X509v3 Basic Constraints, short_name=basicConstraints, oid=2.5.29.19, critical=T, value=CA:FALSE] +[name=X509v3 Extended Key Usage, short_name=extendedKeyUsage, oid=2.5.29.37, critical=F, value=TLS Web Server Authentication, TLS Web Client Authentication] +[name=X509v3 Certificate Policies, short_name=certificatePolicies, oid=2.5.29.32, critical=F, value=Policy: 1.3.6.1.4.1.6449.1.2.1.3.4^J CPS: https://secure.comodo.com/CPS^J] +[name=X509v3 CRL Distribution Points, short_name=crlDistributionPoints, oid=2.5.29.31, critical=F, value=^JFull Name:^J URI:http://crl.comodoca.com/COMODOHigh-AssuranceSecureServerCA.crl^J] +[name=Authority Information Access, short_name=authorityInfoAccess, oid=1.3.6.1.5.5.7.1.1, critical=F, value=CA Issuers - URI:http://crt.comodoca.com/COMODOHigh-AssuranceSecureServerCA.crt^JOCSP - URI:http://ocsp.comodoca.com^J] +[name=X509v3 Subject Alternative Name, short_name=subjectAltName, oid=2.5.29.17, critical=F, value=DNS:*.taleo.net, DNS:taleo.net] +[name=X509v3 Authority Key Identifier, short_name=authorityKeyIdentifier, oid=2.5.29.35, critical=F, value=keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A^J] +[name=X509v3 Subject Key Identifier, short_name=subjectKeyIdentifier, oid=2.5.29.14, critical=F, value=3F:D5:B5:D0:D6:44:79:50:4A:17:A3:9B:8C:4A:DC:B8:B0:22:64:6B] +[name=X509v3 Key Usage, short_name=keyUsage, oid=2.5.29.15, critical=T, value=Certificate Sign, CRL Sign] +[name=X509v3 Basic Constraints, short_name=basicConstraints, oid=2.5.29.19, critical=T, value=CA:TRUE, pathlen:0] +[name=X509v3 Certificate Policies, short_name=certificatePolicies, oid=2.5.29.32, critical=F, value=Policy: X509v3 Any Policy^J] +[name=X509v3 CRL Distribution Points, short_name=crlDistributionPoints, oid=2.5.29.31, critical=F, value=^JFull Name:^J URI:http://crl.usertrust.com/AddTrustExternalCARoot.crl^J] +[name=Authority Information Access, short_name=authorityInfoAccess, oid=1.3.6.1.5.5.7.1.1, critical=F, value=CA Issuers - URI:http://crt.usertrust.com/AddTrustExternalCARoot.p7c^JCA Issuers - URI:http://crt.usertrust.com/AddTrustUTNSGCCA.crt^JOCSP - URI:http://ocsp.usertrust.com^J] +[name=X509v3 Subject Key Identifier, short_name=subjectKeyIdentifier, oid=2.5.29.14, critical=F, value=AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A] +[name=X509v3 Key Usage, short_name=keyUsage, oid=2.5.29.15, critical=F, value=Certificate Sign, CRL Sign] +[name=X509v3 Basic Constraints, short_name=basicConstraints, oid=2.5.29.19, critical=T, value=CA:TRUE] +[name=X509v3 Authority Key Identifier, short_name=authorityKeyIdentifier, oid=2.5.29.35, critical=F, value=keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A^JDirName:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root^Jserial:01^J] diff --git a/testing/btest/scripts/base/protocols/ssl/x509_extensions.test b/testing/btest/scripts/base/protocols/ssl/x509_extensions.test new file mode 100644 index 0000000000..4db3233b27 --- /dev/null +++ b/testing/btest/scripts/base/protocols/ssl/x509_extensions.test @@ -0,0 +1,7 @@ +# @TEST-EXEC: bro -r $TRACES/tls1.2.trace %INPUT +# @TEST-EXEC: btest-diff .stdout + +event x509_extension(c: connection, is_orig: bool, cert:X509, extension: X509_extension_info) +{ + print extension; +} From af95026348688e0df8c867f67d2a53a3d440cf41 Mon Sep 17 00:00:00 2001 From: Jeannette Dopheide Date: Mon, 27 Jan 2014 15:23:24 -0600 Subject: [PATCH 044/254] Minor grammar edits to Installation and Quick Start pages --- doc/install/install.rst | 8 ++++---- doc/quickstart/index.rst | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/install/install.rst b/doc/install/install.rst index 3678d948c2..7030c95642 100644 --- a/doc/install/install.rst +++ b/doc/install/install.rst @@ -89,7 +89,7 @@ Optional Dependencies Bro can make use of some optional libraries and tools if they are found at build time: - * LibGeoIP (for geo-locating IP addresses) + * LibGeoIP (for geolocating IP addresses) * sendmail (enables Bro and BroControl to send mail) * gawk (enables all features of bro-cut) * curl (used by a Bro script that implements active HTTP) @@ -137,11 +137,11 @@ The primary install prefix for binary packages is ``/opt/bro``. Non-MacOS packages that include BroControl also put variable/runtime data (e.g. Bro logs) in ``/var/opt/bro``. -Installing From Source +Installing from Source ========================== -Bro releases are bundled into source packages for convenience and -available from the `bro downloads page`_. Alternatively, the latest +Bro releases are bundled into source packages for convenience and are +available on the `bro downloads page`_. Alternatively, the latest Bro development version can be obtained through git repositories hosted at ``git.bro.org``. See our `git development documentation `_ for comprehensive diff --git a/doc/quickstart/index.rst b/doc/quickstart/index.rst index 49a909a37f..e8ead2cf01 100644 --- a/doc/quickstart/index.rst +++ b/doc/quickstart/index.rst @@ -155,7 +155,7 @@ changes we want to make: attempt looks like it may have been successful, and we want email when that happens, but only for certain servers. -So we've defined *what* we want to do, but need to know *where* to do it. +We've defined *what* we want to do, but need to know *where* to do it. The answer is to use a script written in the Bro programming language, so let's do a quick intro to Bro scripting. @@ -181,7 +181,7 @@ must explicitly choose if they want to load them. The main entry point for the default analysis configuration of a standalone Bro instance managed by BroControl is the ``$PREFIX/share/bro/site/local.bro`` -script. So we'll be adding to that in the following sections, but first +script. We'll be adding to that in the following sections, but first we have to figure out what to add. Redefining Script Option Variables @@ -197,7 +197,7 @@ A redefineable constant might seem strange, but what that really means is that the variable's value may not change at run-time, but whose initial value can be modified via the ``redef`` operator at parse-time. -So let's continue on our path to modify the behavior for the two SSL +Let's continue on our path to modify the behavior for the two SSL and SSH notices. Looking at :doc:`/scripts/base/frameworks/notice/main.bro`, we see that it advertises: @@ -211,7 +211,7 @@ we see that it advertises: const ignored_types: set[Notice::Type] = {} &redef; } -That's exactly what we want to do for the SSL notice. So add to ``local.bro``: +That's exactly what we want to do for the SSL notice. Add to ``local.bro``: .. code:: bro @@ -276,9 +276,9 @@ an email on the condition that the predicate function evaluates to true, which is whenever the notice type is an SSH login and the responding host stored inside the ``Info`` record's connection field is in the set of watched servers. -.. note:: record field member access is done with the '$' character +.. note:: Record field member access is done with the '$' character instead of a '.' as might be expected from other languages, in - order to avoid ambiguity with the builtin address type's use of '.' + order to avoid ambiguity with the built-in address type's use of '.' in IPv4 dotted decimal representations. Remember, to finalize that configuration change perform the ``check``, From 2c7e7f962ea847259a95f04f3360775149d72702 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Tue, 8 Oct 2013 12:50:47 -0700 Subject: [PATCH 045/254] Make x509 certificates an opaque type --- src/SerialTypes.h | 1 + src/Type.h | 1 + src/analyzer/protocol/ssl/ssl-analyzer.pac | 16 --- src/analyzer/protocol/ssl/ssl-protocol.pac | 100 ------------------ .../analyzer/x509/CMakeLists.txt | 2 +- src/file_analysis/analyzer/x509/Plugin.cc | 1 + src/file_analysis/analyzer/x509/X509.cc | 64 +++++++++++ src/file_analysis/analyzer/x509/X509.h | 44 ++++++++ src/main.cc | 2 + 9 files changed, 114 insertions(+), 117 deletions(-) diff --git a/src/SerialTypes.h b/src/SerialTypes.h index 69927afb74..81ccbc030e 100644 --- a/src/SerialTypes.h +++ b/src/SerialTypes.h @@ -111,6 +111,7 @@ SERIAL_VAL(ENTROPY_VAL, 19) SERIAL_VAL(TOPK_VAL, 20) SERIAL_VAL(BLOOMFILTER_VAL, 21) SERIAL_VAL(CARDINALITY_VAL, 22) +SERIAL_VAL(X509_VAL, 23) #define SERIAL_EXPR(name, val) SERIAL_CONST(name, val, EXPR) SERIAL_EXPR(EXPR, 1) diff --git a/src/Type.h b/src/Type.h index a6163d5152..b880eac131 100644 --- a/src/Type.h +++ b/src/Type.h @@ -616,6 +616,7 @@ extern OpaqueType* entropy_type; extern OpaqueType* cardinality_type; extern OpaqueType* topk_type; extern OpaqueType* bloomfilter_type; +extern OpaqueType* x509_opaque_type; // Returns the BRO basic (non-parameterized) type with the given type. extern BroType* base_type(TypeTag tag); diff --git a/src/analyzer/protocol/ssl/ssl-analyzer.pac b/src/analyzer/protocol/ssl/ssl-analyzer.pac index 4bf1e27d64..f9de1a12a8 100644 --- a/src/analyzer/protocol/ssl/ssl-analyzer.pac +++ b/src/analyzer/protocol/ssl/ssl-analyzer.pac @@ -22,8 +22,6 @@ }; 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); %} @@ -33,20 +31,6 @@ string orig_label(bool is_orig) return string(is_orig ? "originator" :"responder"); } - void free_X509(void* cert) - { - X509_free((X509*) cert); - } - - X509* d2i_X509_binpac(X509** px, const uint8** in, int len) - { -#ifdef OPENSSL_D2I_X509_USES_CONST_CHAR - return d2i_X509(px, in, len); -#else - return d2i_X509(px, (u_char**) in, len); -#endif - } - string handshake_type_label(int type) { switch ( type ) { diff --git a/src/analyzer/protocol/ssl/ssl-protocol.pac b/src/analyzer/protocol/ssl/ssl-protocol.pac index b35d07f18b..4f24251a5c 100644 --- a/src/analyzer/protocol/ssl/ssl-protocol.pac +++ b/src/analyzer/protocol/ssl/ssl-protocol.pac @@ -22,7 +22,6 @@ type uint24 = record { }; string state_label(int state_nr); - double get_time_from_asn1(const ASN1_TIME * atime); %} extern type to_int; @@ -146,105 +145,6 @@ enum AnalyzerState { return string(fmt("UNKNOWN (%d)", state_nr)); } } - - - double get_time_from_asn1(const ASN1_TIME * atime) - { - time_t lResult = 0; - - char lBuffer[24]; - char * pBuffer = lBuffer; - - size_t lTimeLength = atime->length; - char * pString = (char *) atime->data; - - if ( atime->type == V_ASN1_UTCTIME ) - { - if ( lTimeLength < 11 || lTimeLength > 17 ) - return 0; - - memcpy(pBuffer, pString, 10); - pBuffer += 10; - pString += 10; - } - else - { - if ( lTimeLength < 13 ) - return 0; - - memcpy(pBuffer, pString, 12); - pBuffer += 12; - pString += 12; - } - - if ((*pString == 'Z') || (*pString == '-') || (*pString == '+')) - { - *(pBuffer++) = '0'; - *(pBuffer++) = '0'; - } - else - { - *(pBuffer++) = *(pString++); - *(pBuffer++) = *(pString++); - - // Skip any fractional seconds... - if (*pString == '.') - { - pString++; - while ((*pString >= '0') && (*pString <= '9')) - pString++; - } - } - - *(pBuffer++) = 'Z'; - *(pBuffer++) = '\0'; - - time_t lSecondsFromUTC; - - if ( *pString == 'Z' ) - lSecondsFromUTC = 0; - - else - { - if ((*pString != '+') && (pString[5] != '-')) - return 0; - - lSecondsFromUTC = ((pString[1]-'0') * 10 + (pString[2]-'0')) * 60; - lSecondsFromUTC += (pString[3]-'0') * 10 + (pString[4]-'0'); - - if (*pString == '-') - lSecondsFromUTC = -lSecondsFromUTC; - } - - tm lTime; - lTime.tm_sec = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0'); - lTime.tm_min = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0'); - lTime.tm_hour = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0'); - lTime.tm_mday = ((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0'); - lTime.tm_mon = (((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0')) - 1; - lTime.tm_year = ((lBuffer[0] - '0') * 10) + (lBuffer[1] - '0'); - - if ( lTime.tm_year < 50 ) - lTime.tm_year += 100; // RFC 2459 - - lTime.tm_wday = 0; - lTime.tm_yday = 0; - lTime.tm_isdst = 0; // No DST adjustment requested - - lResult = mktime(&lTime); - - if ( lResult ) - { - if ( 0 != lTime.tm_isdst ) - lResult -= 3600; // mktime may adjust for DST (OS dependent) - - lResult += lSecondsFromUTC; - } - else - lResult = 0; - - return lResult; - } %} ###################################################################### diff --git a/src/file_analysis/analyzer/x509/CMakeLists.txt b/src/file_analysis/analyzer/x509/CMakeLists.txt index 759a01b55c..b07ef278f7 100644 --- a/src/file_analysis/analyzer/x509/CMakeLists.txt +++ b/src/file_analysis/analyzer/x509/CMakeLists.txt @@ -6,5 +6,5 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} bro_plugin_begin(Bro X509) bro_plugin_cc(X509.cc Plugin.cc ../../Analyzer.cc) -bro_plugin_bif(events.bif types.bif) +bro_plugin_bif(events.bif types.bif functions.bif) bro_plugin_end() diff --git a/src/file_analysis/analyzer/x509/Plugin.cc b/src/file_analysis/analyzer/x509/Plugin.cc index 1e76e3fdb7..5b0e5779c5 100644 --- a/src/file_analysis/analyzer/x509/Plugin.cc +++ b/src/file_analysis/analyzer/x509/Plugin.cc @@ -7,4 +7,5 @@ BRO_PLUGIN_BEGIN(Bro, X509) BRO_PLUGIN_FILE_ANALYZER("X509", X509); BRO_PLUGIN_BIF_FILE(events); BRO_PLUGIN_BIF_FILE(types); + BRO_PLUGIN_BIF_FILE(functions); BRO_PLUGIN_END diff --git a/src/file_analysis/analyzer/x509/X509.cc b/src/file_analysis/analyzer/x509/X509.cc index 3d7871be9a..59ab644634 100644 --- a/src/file_analysis/analyzer/x509/X509.cc +++ b/src/file_analysis/analyzer/x509/X509.cc @@ -17,6 +17,8 @@ using namespace file_analysis; +IMPLEMENT_SERIAL(X509Val, SER_X509_VAL); + file_analysis::X509::X509(RecordVal* args, file_analysis::File* file) : file_analysis::Analyzer(file_mgr->GetComponentTag("X509"), args, file) { @@ -444,3 +446,65 @@ double file_analysis::X509::get_time_from_asn1(const ASN1_TIME * atime) return lResult; } +X509Val::X509Val(::X509* arg_certificate) : OpaqueVal(x509_opaque_type) + { + certificate = arg_certificate; + } + +X509Val::X509Val() : OpaqueVal(x509_opaque_type) + { + certificate = 0; + } + +X509Val::~X509Val() + { + if ( certificate ) + X509_free(certificate); + } + +::X509* X509Val::GetCertificate() const + { + return certificate; + } + +bool X509Val::DoSerialize(SerialInfo* info) const + { + DO_SERIALIZE(SER_X509_VAL, X509Val); + + unsigned char *buf = NULL; + + int length = i2d_X509(certificate, &buf); + + if ( length < 0 ) + return false; + + bool res = SERIALIZE_STR(reinterpret_cast(buf), length); + + OPENSSL_free(buf); + return res; + } + +bool X509Val::DoUnserialize(UnserialInfo* info) + { + DO_UNSERIALIZE(OpaqueVal) + + int length; + unsigned char *certbuf, *opensslbuf; + + if ( ! UNSERIALIZE_STR(reinterpret_cast(&certbuf), &length) ) + return false; + + opensslbuf = certbuf; // OpenSSL likes to shift pointers around. really. + certificate = d2i_X509(NULL, const_cast(&opensslbuf), length); + delete[] certbuf; + + if ( !certificate ) + return false; + + return true; + } + + + + + diff --git a/src/file_analysis/analyzer/x509/X509.h b/src/file_analysis/analyzer/x509/X509.h index cc0131afac..80bb68209e 100644 --- a/src/file_analysis/analyzer/x509/X509.h +++ b/src/file_analysis/analyzer/x509/X509.h @@ -39,6 +39,50 @@ private: std::string cert_data; }; +/** + * This class wraps an OpenSSL X509 data structure. + * + * We need these to be able to pass OpenSSL pointers around in Bro + * script-land. Otherwise, we cannot verify certificates from Bro + * scriptland + */ +class X509Val : public OpaqueVal { +public: + /** + * Construct an X509Val. + * + * @param certificate specifies the wrapped OpenSSL certificate + * + * @return A newly initialized X509Val + */ + X509Val(::X509* certificate); + + /** + * Destructor. + */ + ~X509Val(); + + /** + * Get the wrapped X509 certificate. Please take care, that the + * internal OpenSSL reference counting stays the same. + * + * @return The wrapped OpenSSL X509 certificate + */ + ::X509* GetCertificate() const; + +protected: + /** + * Construct an empty X509Val. Only used for deserialization + */ + X509Val(); + +private: + ::X509* certificate; // the wrapped certificate + + DECLARE_SERIAL(X509Val); +}; + } + #endif diff --git a/src/main.cc b/src/main.cc index 313e1a40b0..ffa7a85f29 100644 --- a/src/main.cc +++ b/src/main.cc @@ -131,6 +131,7 @@ OpaqueType* entropy_type = 0; OpaqueType* cardinality_type = 0; OpaqueType* topk_type = 0; OpaqueType* bloomfilter_type = 0; +OpaqueType* x509_opaque_type = 0; extern std::list docs_generated; @@ -860,6 +861,7 @@ int main(int argc, char** argv) cardinality_type = new OpaqueType("cardinality"); topk_type = new OpaqueType("topk"); bloomfilter_type = new OpaqueType("bloomfilter"); + x509_opaque_type = new OpaqueType("x509"); // The leak-checker tends to produce some false // positives (memory which had already been From 0e0e74e49c01ab867d430d21c149bdf27915b0c3 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 28 Jan 2014 11:04:01 -0600 Subject: [PATCH 046/254] Improve DNS analysis. - Fix parsing of empty question sections (when QDCOUNT == 0). In this case, the DNS parser would extract two 2-byte fields for use in either "dns_query_reply" or "dns_rejected" events (dependent on value of RCODE) as qclass and qtype parameters. This is not correct, because such fields don't actually exist in the DNS message format when QDCOUNT is 0. As a result, these events are no longer raised when there's an empty question section. Scripts that depends on checking for an empty question section can do that in the "dns_message" event. - Add a new "dns_unknown_reply" event, for when Bro does not know how to fully parse a particular resource record type. This helps fix a problem in the default DNS scripts where the logic to complete request-reply pair matching doesn't work because it's waiting on more RR events to complete the reply. i.e. it expects ANCOUNT number of dns_*_reply events and will wait until it gets that many before completing a request-reply pair and logging it to dns.log. This could cause bogus replies to match a previous request if they happen to share a DNS transaction ID. --- scripts/base/protocols/dns/main.bro | 27 +++++++++++++++---- src/analyzer/protocol/dns/DNS.cc | 22 +++++++-------- src/analyzer/protocol/dns/events.bif | 20 ++++++++++++-- .../btest-doc.sphinx.using_bro#1 | 4 +-- .../conn.select | 4 +-- .../dns.log | 6 ++--- .../dns.log | 8 +++--- 7 files changed, 61 insertions(+), 30 deletions(-) diff --git a/scripts/base/protocols/dns/main.bro b/scripts/base/protocols/dns/main.bro index 0d23029ad7..f3f19d488c 100644 --- a/scripts/base/protocols/dns/main.bro +++ b/scripts/base/protocols/dns/main.bro @@ -158,12 +158,17 @@ hook set_session(c: connection, msg: dns_msg, is_query: bool) &priority=5 # If this is either a query or this is the reply but # no Info records are in the queue (we missed the query?) # we need to create an Info record and put it in the queue. - if ( is_query || - Queue::len(c$dns_state$pending[msg$id]) == 0 ) + if ( is_query ) { info = new_session(c, msg$id); Queue::put(c$dns_state$pending[msg$id], info); } + else if ( Queue::len(c$dns_state$pending[msg$id]) == 0 ) + { + info = new_session(c, msg$id); + Queue::put(c$dns_state$pending[msg$id], info); + event conn_weird("dns_unmatched_reply", c, ""); + } if ( is_query ) # If this is a query, assign the newly created info variable @@ -202,17 +207,23 @@ hook set_session(c: connection, msg: dns_msg, is_query: bool) &priority=5 event dns_message(c: connection, is_orig: bool, msg: dns_msg, len: count) &priority=5 { hook set_session(c, msg, is_orig); + + if ( msg$QR && msg$rcode != 0 && msg$num_queries == 0 ) + c$dns$rejected = T; } event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=5 { + if ( ! msg$QR ) + # This is weird: the inquirer must also be providing answers in + # the request, which is not what we want to track. + return; + if ( ans$answer_type == DNS_ANS ) { if ( ! c?$dns ) - { - event conn_weird("dns_unmatched_reply", c, ""); hook set_session(c, msg, F); - } + c$dns$AA = msg$AA; c$dns$RA = msg$RA; @@ -265,6 +276,12 @@ event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qcla c$dns$query = query; } + +event dns_unknown_reply(c: connection, msg: dns_msg, ans: dns_answer) &priority=5 + { + event DNS::do_reply(c, msg, ans, fmt("", ans$qtype)); + } + event dns_A_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5 { event DNS::do_reply(c, msg, ans, fmt("%s", a)); diff --git a/src/analyzer/protocol/dns/DNS.cc b/src/analyzer/protocol/dns/DNS.cc index 806cb9ae75..b17a90dd61 100644 --- a/src/analyzer/protocol/dns/DNS.cc +++ b/src/analyzer/protocol/dns/DNS.cc @@ -137,18 +137,6 @@ int DNS_Interpreter::ParseQuestions(DNS_MsgInfo* msg, { int n = msg->qdcount; - if ( n == 0 ) - { - // Generate event here because we won't go into ParseQuestion. - EventHandlerPtr dns_event = - msg->rcode == DNS_CODE_OK ? - dns_query_reply : dns_rejected; - BroString* question_name = new BroString(""); - - SendReplyOrRejectEvent(msg, dns_event, data, len, question_name); - return 1; - } - while ( n > 0 && ParseQuestion(msg, data, len, msg_start) ) --n; return n == 0; @@ -299,6 +287,16 @@ int DNS_Interpreter::ParseAnswer(DNS_MsgInfo* msg, break; default: + + if ( dns_unknown_reply && ! msg->skip_event ) + { + val_list* vl = new val_list; + vl->append(analyzer->BuildConnVal()); + vl->append(msg->BuildHdrVal()); + vl->append(msg->BuildAnswerVal()); + analyzer->ConnectionEvent(dns_unknown_reply, vl); + } + analyzer->Weird("DNS_RR_unknown_type"); data += rdlength; len -= rdlength; diff --git a/src/analyzer/protocol/dns/events.bif b/src/analyzer/protocol/dns/events.bif index 95c604a8b8..b43ac95f66 100644 --- a/src/analyzer/protocol/dns/events.bif +++ b/src/analyzer/protocol/dns/events.bif @@ -50,7 +50,7 @@ event dns_message%(c: connection, is_orig: bool, msg: dns_msg, len: count%); event dns_request%(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count%); ## Generated for DNS replies that reject a query. This event is raised if a DNS -## reply either indicates failure via its status code or does not pass on any +## reply indicates failure because it does not pass on any ## answers to a query. Note that all of the event's parameters are parsed out of ## the reply; there's no stateful correlation with the query. ## @@ -78,7 +78,7 @@ event dns_request%(c: connection, msg: dns_msg, query: string, qtype: count, qcl ## dns_skip_all_addl dns_skip_all_auth dns_skip_auth event dns_rejected%(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count%); -## Generated for DNS replies with an *ok* status code but no question section. +## Generated for each entry in the Question section of a DNS reply. ## ## See `Wikipedia `__ for more ## information about the DNS protocol. Bro analyzes both UDP and TCP DNS @@ -401,6 +401,22 @@ event dns_TXT_reply%(c: connection, msg: dns_msg, ans: dns_answer, str: string%) ## dns_skip_addl dns_skip_all_addl dns_skip_all_auth dns_skip_auth event dns_SRV_reply%(c: connection, msg: dns_msg, ans: dns_answer%); +## Generated on DNS reply resource records when the type of record is not one +## that Bro knows how to parse and generate another more specific specific +## event. +## +## c: The connection, which may be UDP or TCP depending on the type of the +## transport-layer session being analyzed. +## +## msg: The parsed DNS message header. +## +## ans: The type-independent part of the parsed answer record. +## +## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl +## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply +## dns_TSIG_addl dns_TXT_reply dns_WKS_reply dns_SRV_reply dns_end +event dns_unknown_reply%(c: connection, msg: dns_msg, ans: dns_answer%); + ## Generated for DNS replies of type *EDNS*. For replies with multiple answers, ## an individual event of the corresponding type is raised for each. ## diff --git a/testing/btest/Baseline/doc.sphinx.using_bro/btest-doc.sphinx.using_bro#1 b/testing/btest/Baseline/doc.sphinx.using_bro/btest-doc.sphinx.using_bro#1 index 65c802ccf2..53bcb5581d 100644 --- a/testing/btest/Baseline/doc.sphinx.using_bro/btest-doc.sphinx.using_bro#1 +++ b/testing/btest/Baseline/doc.sphinx.using_bro/btest-doc.sphinx.using_bro#1 @@ -20,8 +20,8 @@ #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents #types time string addr port addr port enum string interval count count string bool count string count count count count table[string] 1300475167.096535 CXWv6p3arKYeMETxOg 141.142.220.202 5353 224.0.0.251 5353 udp dns - - - S0 - 0 D 1 73 0 0 (empty) - 1300475167.097012 CjhGID4nQcgTWjvg4c fe80::217:f2ff:fed7:cf65 5353 ff02::fb 5353 udp - - - - S0 - 0 D 1 199 0 0 (empty) - 1300475167.099816 CCvvfg3TEfuqmmG4bh 141.142.220.50 5353 224.0.0.251 5353 udp - - - - S0 - 0 D 1 179 0 0 (empty) + 1300475167.097012 CjhGID4nQcgTWjvg4c fe80::217:f2ff:fed7:cf65 5353 ff02::fb 5353 udp dns - - - S0 - 0 D 1 199 0 0 (empty) + 1300475167.099816 CCvvfg3TEfuqmmG4bh 141.142.220.50 5353 224.0.0.251 5353 udp dns - - - S0 - 0 D 1 179 0 0 (empty) 1300475168.853899 CPbrpk1qSsw6ESzHV4 141.142.220.118 43927 141.142.2.2 53 udp dns 0.000435 38 89 SF - 0 Dd 1 66 1 117 (empty) 1300475168.854378 C6pKV8GSxOnSLghOa 141.142.220.118 37676 141.142.2.2 53 udp dns 0.000420 52 99 SF - 0 Dd 1 80 1 127 (empty) 1300475168.854837 CIPOse170MGiRM1Qf4 141.142.220.118 40526 141.142.2.2 53 udp dns 0.000392 38 183 SF - 0 Dd 1 66 1 211 (empty) diff --git a/testing/btest/Baseline/scripts.base.frameworks.logging.sqlite.wikipedia/conn.select b/testing/btest/Baseline/scripts.base.frameworks.logging.sqlite.wikipedia/conn.select index bdae1a8f73..8653fd1edb 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.logging.sqlite.wikipedia/conn.select +++ b/testing/btest/Baseline/scripts.base.frameworks.logging.sqlite.wikipedia/conn.select @@ -1,6 +1,6 @@ 1300475167.09653|CXWv6p3arKYeMETxOg|141.142.220.202|5353|224.0.0.251|5353|udp|dns||||S0||0|D|1|73|0|0|(empty) -1300475167.09701|CjhGID4nQcgTWjvg4c|fe80::217:f2ff:fed7:cf65|5353|ff02::fb|5353|udp|||||S0||0|D|1|199|0|0|(empty) -1300475167.09982|CCvvfg3TEfuqmmG4bh|141.142.220.50|5353|224.0.0.251|5353|udp|||||S0||0|D|1|179|0|0|(empty) +1300475167.09701|CjhGID4nQcgTWjvg4c|fe80::217:f2ff:fed7:cf65|5353|ff02::fb|5353|udp|dns||||S0||0|D|1|199|0|0|(empty) +1300475167.09982|CCvvfg3TEfuqmmG4bh|141.142.220.50|5353|224.0.0.251|5353|udp|dns||||S0||0|D|1|179|0|0|(empty) 1300475168.652|CsRx2w45OKnoww6xl4|141.142.220.118|35634|208.80.152.2|80|tcp||0.0613288879394531|463|350|OTH||0|DdA|2|567|1|402|(empty) 1300475168.72401|CRJuHdVW0XPVINV8a|141.142.220.118|48649|208.80.152.118|80|tcp|http|0.1199049949646|525|232|S1||0|ShADad|4|741|3|396|(empty) 1300475168.8539|CPbrpk1qSsw6ESzHV4|141.142.220.118|43927|141.142.2.2|53|udp|dns|0.000435113906860352|38|89|SF||0|Dd|1|66|1|117|(empty) diff --git a/testing/btest/Baseline/scripts.base.protocols.dns.dns-key/dns.log b/testing/btest/Baseline/scripts.base.protocols.dns.dns-key/dns.log index 35289b82dd..76e83452e5 100644 --- a/testing/btest/Baseline/scripts.base.protocols.dns.dns-key/dns.log +++ b/testing/btest/Baseline/scripts.base.protocols.dns.dns-key/dns.log @@ -3,8 +3,8 @@ #empty_field (empty) #unset_field - #path dns -#open 2013-08-26-19-04-08 +#open 2014-01-28-14-55-04 #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto trans_id query qclass qclass_name qtype qtype_name rcode rcode_name AA TC RD RA Z answers TTLs rejected #types time string addr port addr port enum count string count string count string count string bool bool bool bool count vector[string] vector[interval] bool -1359565680.761790 CXWv6p3arKYeMETxOg 192.168.6.10 53209 192.168.129.36 53 udp 41477 paypal.com 1 C_INTERNET 48 DNSKEY 0 NOERROR F F T F 1 - - F -#close 2013-08-26-19-04-08 +1359565680.761790 CXWv6p3arKYeMETxOg 192.168.6.10 53209 192.168.129.36 53 udp 41477 paypal.com 1 C_INTERNET 48 DNSKEY 0 NOERROR F F T T 1 ,,, 455.000000,455.000000,455.000000,455.000000 F +#close 2014-01-28-14-55-04 diff --git a/testing/btest/Baseline/scripts.base.protocols.dns.duplicate-reponses/dns.log b/testing/btest/Baseline/scripts.base.protocols.dns.duplicate-reponses/dns.log index 6af017fa49..6e2a0a4699 100644 --- a/testing/btest/Baseline/scripts.base.protocols.dns.duplicate-reponses/dns.log +++ b/testing/btest/Baseline/scripts.base.protocols.dns.duplicate-reponses/dns.log @@ -3,9 +3,9 @@ #empty_field (empty) #unset_field - #path dns -#open 2013-08-26-19-04-08 +#open 2014-01-28-14-58-56 #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto trans_id query qclass qclass_name qtype qtype_name rcode rcode_name AA TC RD RA Z answers TTLs rejected #types time string addr port addr port enum count string count string count string count string bool bool bool bool count vector[string] vector[interval] bool -1363716396.798072 CXWv6p3arKYeMETxOg 55.247.223.174 27285 222.195.43.124 53 udp 21140 www.cmu.edu 1 C_INTERNET 1 A 0 NOERROR T F F F 1 www-cmu.andrew.cmu.edu,www-cmu-2.andrew.cmu.edu,128.2.10.163,www-cmu.andrew.cmu.edu 86400.000000,5.000000,21600.000000,86400.000000 F -1363716396.798374 CXWv6p3arKYeMETxOg 55.247.223.174 27285 222.195.43.124 53 udp 21140 - - - - - 0 NOERROR T F F F 0 www-cmu-2.andrew.cmu.edu,128.2.10.163 5.000000,21600.000000 F -#close 2013-08-26-19-04-08 +1363716396.798072 CXWv6p3arKYeMETxOg 55.247.223.174 27285 222.195.43.124 53 udp 21140 www.cmu.edu 1 C_INTERNET 1 A 0 NOERROR T F F F 1 www-cmu.andrew.cmu.edu,,www-cmu-2.andrew.cmu.edu,128.2.10.163 86400.000000,86400.000000,5.000000,21600.000000 F +1363716396.798374 CXWv6p3arKYeMETxOg 55.247.223.174 27285 222.195.43.124 53 udp 21140 - - - - - 0 NOERROR T F F F 0 www-cmu.andrew.cmu.edu,,www-cmu-2.andrew.cmu.edu,128.2.10.163 86400.000000,86400.000000,5.000000,21600.000000 F +#close 2014-01-28-14-58-56 From 31866f8f59ba9f9ec31543d4983f06152ec98bda Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 28 Jan 2014 13:56:22 -0600 Subject: [PATCH 047/254] Change dns.log to include only standard DNS queries. The scope of dns.log is now only standard queries (OPCODE == 0). Other kinds of queries (e.g. inverse query) were not handled correctly and could interfere with the state tracking of the default DNS scripts. --- doc/scripting/connection_record_02.bro | 2 +- doc/scripting/index.rst | 14 +++++++------- scripts/base/protocols/dns/main.bro | 17 +++++++++++++++-- scripts/policy/protocols/dns/auth-addl.bro | 4 ++++ .../btest-doc.sphinx.connection-record-01#1 | 6 +++--- .../btest-doc.sphinx.connection-record-02#1 | 14 ++++++-------- .../output | 2 +- .../dns.log | 10 ---------- ...s-session.trace => dns-inverse-query.trace} | Bin .../doc/sphinx/connection-record-01.btest | 2 +- .../doc/sphinx/connection-record-02.btest | 2 +- ...oc_scripting_connection_record_02_bro.btest | 2 +- .../policy/protocols/dns/event-priority.bro | 4 ---- .../policy/protocols/dns/inverse-request.bro | 4 ++++ 14 files changed, 44 insertions(+), 39 deletions(-) delete mode 100644 testing/btest/Baseline/scripts.policy.protocols.dns.event-priority/dns.log rename testing/btest/Traces/{dns-session.trace => dns-inverse-query.trace} (100%) delete mode 100644 testing/btest/scripts/policy/protocols/dns/event-priority.bro create mode 100644 testing/btest/scripts/policy/protocols/dns/inverse-request.bro diff --git a/doc/scripting/connection_record_02.bro b/doc/scripting/connection_record_02.bro index 4459e47ef6..e4770069a9 100644 --- a/doc/scripting/connection_record_02.bro +++ b/doc/scripting/connection_record_02.bro @@ -1,5 +1,5 @@ @load base/protocols/conn -@load base/protocols/dns +@load base/protocols/http event connection_state_remove(c: connection) { diff --git a/doc/scripting/index.rst b/doc/scripting/index.rst index e42aa55e2c..66ebce86af 100644 --- a/doc/scripting/index.rst +++ b/doc/scripting/index.rst @@ -232,7 +232,7 @@ overly populated. .. btest:: connection-record-01 - @TEST-EXEC: btest-rst-cmd bro -b -r ${TRACES}/dns-session.trace ${DOC_ROOT}/scripting/connection_record_01.bro + @TEST-EXEC: btest-rst-cmd bro -b -r ${TRACES}/http/get.trace ${DOC_ROOT}/scripting/connection_record_01.bro As you can see from the output, the connection record is something of a jumble when printed on its own. Regularly taking a peek at a @@ -248,9 +248,9 @@ originating host is referenced by ``c$id$orig_h`` which if given a narrative relates to ``orig_h`` which is a member of ``id`` which is a member of the data structure referred to as ``c`` that was passed into the event handler." Given that the responder port -(``c$id$resp_p``) is ``53/tcp``, it's likely that Bro's base DNS scripts +(``c$id$resp_p``) is ``53/tcp``, it's likely that Bro's base HTTP scripts can further populate the connection record. Let's load the -``base/protocols/dns`` scripts and check the output of our script. +``base/protocols/http`` scripts and check the output of our script. Bro uses the dollar sign as its field delimiter and a direct correlation exists between the output of the connection record and the @@ -262,16 +262,16 @@ brackets, which would correspond to the ``$``-delimiter in a Bro script. .. btest:: connection-record-02 - @TEST-EXEC: btest-rst-cmd bro -b -r ${TRACES}/dns-session.trace ${DOC_ROOT}/scripting/connection_record_02.bro + @TEST-EXEC: btest-rst-cmd bro -b -r ${TRACES}/http/get.trace ${DOC_ROOT}/scripting/connection_record_02.bro -The addition of the ``base/protocols/dns`` scripts populates the -``dns=[]`` member of the connection record. While Bro is doing a +The addition of the ``base/protocols/http`` scripts populates the +``http=[]`` member of the connection record. While Bro is doing a massive amount of work in the background, it is in what is commonly called "scriptland" that details are being refined and decisions being made. Were we to continue running in "bare mode" we could slowly keep adding infrastructure through ``@load`` statements. For example, were we to ``@load base/frameworks/logging``, Bro would generate a -``conn.log`` and ``dns.log`` for us in the current working directory. +``conn.log`` and ``http.log`` for us in the current working directory. As mentioned above, including the appropriate ``@load`` statements is not only good practice, but can also help to indicate which functionalities are being used in a script. Take a second to run the diff --git a/scripts/base/protocols/dns/main.bro b/scripts/base/protocols/dns/main.bro index f3f19d488c..0651e23ada 100644 --- a/scripts/base/protocols/dns/main.bro +++ b/scripts/base/protocols/dns/main.bro @@ -206,6 +206,10 @@ hook set_session(c: connection, msg: dns_msg, is_query: bool) &priority=5 event dns_message(c: connection, is_orig: bool, msg: dns_msg, len: count) &priority=5 { + if ( msg$opcode != 0 ) + # Currently only standard queries are tracked. + return; + hook set_session(c, msg, is_orig); if ( msg$QR && msg$rcode != 0 && msg$num_queries == 0 ) @@ -214,6 +218,10 @@ event dns_message(c: connection, is_orig: bool, msg: dns_msg, len: count) &prior event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=5 { + if ( msg$opcode != 0 ) + # Currently only standard queries are tracked. + return; + if ( ! msg$QR ) # This is weird: the inquirer must also be providing answers in # the request, which is not what we want to track. @@ -249,7 +257,7 @@ event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=-5 { - if ( c$dns$ready ) + if ( c?$dns && c$dns$ready ) { Log::write(DNS::LOG, c$dns); # This record is logged and no longer pending. @@ -260,6 +268,10 @@ event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count) &priority=5 { + if ( msg$opcode != 0 ) + # Currently only standard queries are tracked. + return; + c$dns$RD = msg$RD; c$dns$TC = msg$TC; c$dns$qclass = qclass; @@ -356,7 +368,8 @@ event dns_SRV_reply(c: connection, msg: dns_msg, ans: dns_answer) &priority=5 event dns_rejected(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count) &priority=5 { - c$dns$rejected = T; + if ( c?$dns ) + c$dns$rejected = T; } event connection_state_remove(c: connection) &priority=-5 diff --git a/scripts/policy/protocols/dns/auth-addl.bro b/scripts/policy/protocols/dns/auth-addl.bro index 8c04379c1c..bc97d529cd 100644 --- a/scripts/policy/protocols/dns/auth-addl.bro +++ b/scripts/policy/protocols/dns/auth-addl.bro @@ -21,6 +21,10 @@ export { event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=4 { + if ( msg$opcode != 0 ) + # Currently only standard queries are tracked. + return; + # The "ready" flag will be set here. This causes the setting from the # base script to be overridden since the base script will log immediately # after all of the ANS replies have been seen. diff --git a/testing/btest/Baseline/doc.sphinx.connection-record-01/btest-doc.sphinx.connection-record-01#1 b/testing/btest/Baseline/doc.sphinx.connection-record-01/btest-doc.sphinx.connection-record-01#1 index 1deb2583a9..8da50c3d30 100644 --- a/testing/btest/Baseline/doc.sphinx.connection-record-01/btest-doc.sphinx.connection-record-01#1 +++ b/testing/btest/Baseline/doc.sphinx.connection-record-01/btest-doc.sphinx.connection-record-01#1 @@ -4,10 +4,10 @@ :linenos: :emphasize-lines: 1,1 - # bro -b -r dns-session.trace connection_record_01.bro - [id=[orig_h=212.180.42.100, orig_p=25000/tcp, resp_h=131.243.64.3, resp_p=53/tcp], orig=[size=29, state=5, num_pkts=6, num_bytes_ip=273, flow_label=0], resp=[size=44, state=5, num_pkts=5, num_bytes_ip=248, flow_label=0], start_time=930613226.067666, duration=0.709643, service={ + # bro -b -r http/get.trace connection_record_01.bro + [id=[orig_h=141.142.228.5, orig_p=59856/tcp, resp_h=192.150.187.43, resp_p=80/tcp], orig=[size=136, state=5, num_pkts=7, num_bytes_ip=512, flow_label=0], resp=[size=5007, state=5, num_pkts=7, num_bytes_ip=5379, flow_label=0], start_time=1362692526.869344, duration=0.211484, service={ - }, addl=, hot=0, history=ShADadFf, uid=CXWv6p3arKYeMETxOg, tunnel=, conn=[ts=930613226.067666, uid=CXWv6p3arKYeMETxOg, id=[orig_h=212.180.42.100, orig_p=25000/tcp, resp_h=131.243.64.3, resp_p=53/tcp], proto=tcp, service=, duration=0.709643, orig_bytes=29, resp_bytes=44, conn_state=SF, local_orig=, missed_bytes=0, history=ShADadFf, orig_pkts=6, orig_ip_bytes=273, resp_pkts=5, resp_ip_bytes=248, tunnel_parents={ + }, addl=, hot=0, history=ShADadFf, uid=CXWv6p3arKYeMETxOg, tunnel=, conn=[ts=1362692526.869344, uid=CXWv6p3arKYeMETxOg, id=[orig_h=141.142.228.5, orig_p=59856/tcp, resp_h=192.150.187.43, resp_p=80/tcp], proto=tcp, service=, duration=0.211484, orig_bytes=136, resp_bytes=5007, conn_state=SF, local_orig=, missed_bytes=0, history=ShADadFf, orig_pkts=7, orig_ip_bytes=512, resp_pkts=7, resp_ip_bytes=5379, tunnel_parents={ }], extract_orig=F, extract_resp=F] diff --git a/testing/btest/Baseline/doc.sphinx.connection-record-02/btest-doc.sphinx.connection-record-02#1 b/testing/btest/Baseline/doc.sphinx.connection-record-02/btest-doc.sphinx.connection-record-02#1 index 42d0a56e21..c170dbc645 100644 --- a/testing/btest/Baseline/doc.sphinx.connection-record-02/btest-doc.sphinx.connection-record-02#1 +++ b/testing/btest/Baseline/doc.sphinx.connection-record-02/btest-doc.sphinx.connection-record-02#1 @@ -4,16 +4,14 @@ :linenos: :emphasize-lines: 1,1 - # bro -b -r dns-session.trace connection_record_02.bro - [id=[orig_h=212.180.42.100, orig_p=25000/tcp, resp_h=131.243.64.3, resp_p=53/tcp], orig=[size=29, state=5, num_pkts=6, num_bytes_ip=273, flow_label=0], resp=[size=44, state=5, num_pkts=5, num_bytes_ip=248, flow_label=0], start_time=930613226.067666, duration=0.709643, service={ + # bro -b -r http/get.trace connection_record_02.bro + [id=[orig_h=141.142.228.5, orig_p=59856/tcp, resp_h=192.150.187.43, resp_p=80/tcp], orig=[size=136, state=5, num_pkts=7, num_bytes_ip=512, flow_label=0], resp=[size=5007, state=5, num_pkts=7, num_bytes_ip=5379, flow_label=0], start_time=1362692526.869344, duration=0.211484, service={ - }, addl=, hot=0, history=ShADadFf, uid=CXWv6p3arKYeMETxOg, tunnel=, conn=[ts=930613226.067666, uid=CXWv6p3arKYeMETxOg, id=[orig_h=212.180.42.100, orig_p=25000/tcp, resp_h=131.243.64.3, resp_p=53/tcp], proto=tcp, service=, duration=0.709643, orig_bytes=29, resp_bytes=44, conn_state=SF, local_orig=, missed_bytes=0, history=ShADadFf, orig_pkts=6, orig_ip_bytes=273, resp_pkts=5, resp_ip_bytes=248, tunnel_parents={ + }, addl=, hot=0, history=ShADadFf, uid=CXWv6p3arKYeMETxOg, tunnel=, conn=[ts=1362692526.869344, uid=CXWv6p3arKYeMETxOg, id=[orig_h=141.142.228.5, orig_p=59856/tcp, resp_h=192.150.187.43, resp_p=80/tcp], proto=tcp, service=, duration=0.211484, orig_bytes=136, resp_bytes=5007, conn_state=SF, local_orig=, missed_bytes=0, history=ShADadFf, orig_pkts=7, orig_ip_bytes=512, resp_pkts=7, resp_ip_bytes=5379, tunnel_parents={ - }], extract_orig=F, extract_resp=F, dns=, dns_state=[pending={ - [34798] = [initialized=T, vals={ + }], extract_orig=F, extract_resp=F, http=[ts=1362692526.939527, uid=CXWv6p3arKYeMETxOg, id=[orig_h=141.142.228.5, orig_p=59856/tcp, resp_h=192.150.187.43, resp_p=80/tcp], trans_depth=1, method=GET, host=bro.org, uri=/download/CHANGES.bro-aux.txt, referrer=, user_agent=Wget/1.14 (darwin12.2.0), request_body_len=0, response_body_len=4705, status_code=200, status_msg=OK, info_code=, info_msg=, filename=, tags={ - }, settings=[max_len=], top=1, bottom=1, size=0] - }, finished_answers={ + }, username=, password=, capture_password=F, proxied=, range_request=F, orig_fuids=, orig_mime_types=, resp_fuids=[FakNcS1Jfe01uljb3], resp_mime_types=[text/plain], current_entity=, orig_mime_depth=1, resp_mime_depth=1], http_state=[pending={ - }]] + }, current_request=1, current_response=1]] diff --git a/testing/btest/Baseline/doc.sphinx.include-doc_scripting_connection_record_02_bro/output b/testing/btest/Baseline/doc.sphinx.include-doc_scripting_connection_record_02_bro/output index e4552b8580..12092ee2a0 100644 --- a/testing/btest/Baseline/doc.sphinx.include-doc_scripting_connection_record_02_bro/output +++ b/testing/btest/Baseline/doc.sphinx.include-doc_scripting_connection_record_02_bro/output @@ -3,7 +3,7 @@ connection_record_02.bro @load base/protocols/conn -@load base/protocols/dns +@load base/protocols/http event connection_state_remove(c: connection) { diff --git a/testing/btest/Baseline/scripts.policy.protocols.dns.event-priority/dns.log b/testing/btest/Baseline/scripts.policy.protocols.dns.event-priority/dns.log deleted file mode 100644 index 18d5769abf..0000000000 --- a/testing/btest/Baseline/scripts.policy.protocols.dns.event-priority/dns.log +++ /dev/null @@ -1,10 +0,0 @@ -#separator \x09 -#set_separator , -#empty_field (empty) -#unset_field - -#path dns -#open 2013-08-26-19-04-37 -#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto trans_id query qclass qclass_name qtype qtype_name rcode rcode_name AA TC RD RA Z answers TTLs rejected auth addl -#types time string addr port addr port enum count string count string count string count string bool bool bool bool count vector[string] vector[interval] bool table[string] table[string] -930613226.518174 CXWv6p3arKYeMETxOg 212.180.42.100 25000 131.243.64.3 53 tcp 34798 - - - - - 0 NOERROR F F F T 0 4.3.2.1 31337.000000 F - - -#close 2013-08-26-19-04-37 diff --git a/testing/btest/Traces/dns-session.trace b/testing/btest/Traces/dns-inverse-query.trace similarity index 100% rename from testing/btest/Traces/dns-session.trace rename to testing/btest/Traces/dns-inverse-query.trace diff --git a/testing/btest/doc/sphinx/connection-record-01.btest b/testing/btest/doc/sphinx/connection-record-01.btest index b379fb4fbe..3704d58932 100644 --- a/testing/btest/doc/sphinx/connection-record-01.btest +++ b/testing/btest/doc/sphinx/connection-record-01.btest @@ -1 +1 @@ -@TEST-EXEC: btest-rst-cmd bro -b -r ${TRACES}/dns-session.trace ${DOC_ROOT}/scripting/connection_record_01.bro +@TEST-EXEC: btest-rst-cmd bro -b -r ${TRACES}/http/get.trace ${DOC_ROOT}/scripting/connection_record_01.bro diff --git a/testing/btest/doc/sphinx/connection-record-02.btest b/testing/btest/doc/sphinx/connection-record-02.btest index 292503e12c..0b0c87c1f2 100644 --- a/testing/btest/doc/sphinx/connection-record-02.btest +++ b/testing/btest/doc/sphinx/connection-record-02.btest @@ -1 +1 @@ -@TEST-EXEC: btest-rst-cmd bro -b -r ${TRACES}/dns-session.trace ${DOC_ROOT}/scripting/connection_record_02.bro +@TEST-EXEC: btest-rst-cmd bro -b -r ${TRACES}/http/get.trace ${DOC_ROOT}/scripting/connection_record_02.bro diff --git a/testing/btest/doc/sphinx/include-doc_scripting_connection_record_02_bro.btest b/testing/btest/doc/sphinx/include-doc_scripting_connection_record_02_bro.btest index e4552b8580..12092ee2a0 100644 --- a/testing/btest/doc/sphinx/include-doc_scripting_connection_record_02_bro.btest +++ b/testing/btest/doc/sphinx/include-doc_scripting_connection_record_02_bro.btest @@ -3,7 +3,7 @@ connection_record_02.bro @load base/protocols/conn -@load base/protocols/dns +@load base/protocols/http event connection_state_remove(c: connection) { diff --git a/testing/btest/scripts/policy/protocols/dns/event-priority.bro b/testing/btest/scripts/policy/protocols/dns/event-priority.bro deleted file mode 100644 index 2165b102e8..0000000000 --- a/testing/btest/scripts/policy/protocols/dns/event-priority.bro +++ /dev/null @@ -1,4 +0,0 @@ -# @TEST-EXEC: bro -r $TRACES/dns-session.trace %INPUT -# @TEST-EXEC: btest-diff dns.log - -@load protocols/dns/auth-addl diff --git a/testing/btest/scripts/policy/protocols/dns/inverse-request.bro b/testing/btest/scripts/policy/protocols/dns/inverse-request.bro new file mode 100644 index 0000000000..d695060707 --- /dev/null +++ b/testing/btest/scripts/policy/protocols/dns/inverse-request.bro @@ -0,0 +1,4 @@ +# @TEST-EXEC: bro -r $TRACES/dns-inverse-query.trace %INPUT +# @TEST-EXEC: test ! -e dns.log + +@load protocols/dns/auth-addl From 62b3cb0a5b7bdd8fed1d7d0dae3337115b2feae7 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Tue, 28 Jan 2014 12:28:12 -0800 Subject: [PATCH 048/254] Also use exec-module test to check for leaks. --- testing/btest/core/leaks/exec.test | 80 ++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 testing/btest/core/leaks/exec.test diff --git a/testing/btest/core/leaks/exec.test b/testing/btest/core/leaks/exec.test new file mode 100644 index 0000000000..887ab01d39 --- /dev/null +++ b/testing/btest/core/leaks/exec.test @@ -0,0 +1,80 @@ +# Needs perftools support. +# +# @TEST-GROUP: leaks +# +# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks +# +# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -b ../exectest.bro +# @TEST-EXEC: btest-bg-wait 15 + +@TEST-START-FILE exectest.bro + +@load base/utils/exec +@load base/frameworks/communication # let network-time run. otherwise there are no heartbeats... +redef exit_only_after_terminate = T; + +global c: count = 0; + +function check_exit_condition() + { + c += 1; + + if ( c == 3 ) + terminate(); + } + +function test_cmd(label: string, cmd: Exec::Command) + { + when ( local result = Exec::run(cmd) ) + { + print label, result; + check_exit_condition(); + } + } + +event bro_init() + { + test_cmd("test1", [$cmd="bash ../somescript.sh", + $read_files=set("out1", "out2")]); + test_cmd("test2", [$cmd="bash ../nofiles.sh"]); + # Not sure of a portable way to test signals yet. + #test_cmd("test3", [$cmd="bash ../suicide.sh"]); + test_cmd("test4", [$cmd="bash ../stdin.sh", $stdin="hibye"]); + } + +@TEST-END-FILE + +@TEST-START-FILE somescript.sh +#! /usr/bin/env bash +echo "insert text here" > out1 +echo "and here" >> out1 +echo "insert more text here" > out2 +echo "and there" >> out2 +echo "done" +echo "exit" +echo "stop" +@TEST-END-FILE + +@TEST-START-FILE nofiles.sh +#! /usr/bin/env bash +echo "here's something on stdout" +echo "some more stdout" +echo "last stdout" +echo "and some stderr" 1>&2 +echo "more stderr" 1>&2 +echo "last stderr" 1>&2 +exit 1 +@TEST-END-FILE + +@TEST-START-FILE suicide.sh +#! /usr/bin/env bash +echo "FML" +kill -9 $$ +echo "nope" +@TEST-END-FILE + +@TEST-START-FILE stdin.sh +#! /usr/bin/env bash +read -r line +echo "$line" +@TEST-END-FILE From 55a8725ce28891b8ea4a470334c093f4396566b5 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Wed, 29 Jan 2014 08:42:48 -0800 Subject: [PATCH 049/254] Updating submodule(s). [nomail] --- aux/broctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/broctl b/aux/broctl index c4b5fb7336..9ff2e2ced6 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit c4b5fb7336f2b598cf69777a7ec91b4aa16cacd1 +Subproject commit 9ff2e2ced64a3bd4af1268154e261671a1153481 From 4c52c378d5873abb052d688251f0ec7f5aa1c514 Mon Sep 17 00:00:00 2001 From: Jeannette Dopheide Date: Wed, 29 Jan 2014 11:23:31 -0600 Subject: [PATCH 050/254] Added some grammar and spelling corrections to Installation and Quick Start Guide. --- doc/install/guidelines.rst | 35 +++++++++++++++++------------------ doc/install/install.rst | 4 ++-- doc/quickstart/index.rst | 2 +- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/doc/install/guidelines.rst b/doc/install/guidelines.rst index 7835c83716..2e56b1b17e 100644 --- a/doc/install/guidelines.rst +++ b/doc/install/guidelines.rst @@ -12,32 +12,31 @@ local customizations over. In the following we summarize general guidelines for upgrading, see the :ref:`release-notes` for version-specific information. -Re-Using Previous Install Prefix +Reusing Previous Install Prefix ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you choose to configure and install Bro with the same prefix directory as before, local customization and configuration to files in ``$prefix/share/bro/site`` and ``$prefix/etc`` won't be overwritten (``$prefix`` indicating the root of where Bro was installed). Also, logs -generated at run-time won't be touched by the upgrade. (But making -a backup of local changes before upgrading is still recommended.) +generated at run-time won't be touched by the upgrade. Backing up local +changes before upgrading is still recommended. After upgrading, remember to check ``$prefix/share/bro/site`` and -``$prefix/etc`` for ``.example`` files, which indicate the -distribution's version of the file differs from the local one, which may -include local changes. Review the differences, and make adjustments -as necessary (for differences that aren't the result of a local change, -use the new version's). +``$prefix/etc`` for ``.example`` files, which indicate that the +distribution's version of the file differs from the local one, and therefore, +may include local changes. Review the differences and make adjustments +as necessary. Use the new version for differences that aren't a result of +a local change. -Using a New Install prefix +Using a New Install Prefix ~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you want to install the newer version in a different prefix -directory than before, you can just copy local customization and -configuration files from ``$prefix/share/bro/site`` and ``$prefix/etc`` -to the new location (``$prefix`` indicating the root of where Bro was -originally installed). Make sure to review the files for difference -before copying and make adjustments as necessary (for differences that -aren't the result of a local change, use the new version's). Of -particular note, the copied version of ``$prefix/etc/broctl.cfg`` is -likely to need changes to the ``SpoolDir`` and ``LogDir`` settings. +To install the newer version in a different prefix directory than before, +copy local customization and configuration files from ``$prefix/share/bro/site`` +and ``$prefix/etc`` to the new location (``$prefix`` indicating the root of +where Bro was originally installed). Review the files for differences +before copying and make adjustments as necessary (use the new version for +differences that aren't a result of a local change). Of particular note, +the copied version of ``$prefix/etc/broctl.cfg`` is likely to need changes +to the ``SpoolDir`` and ``LogDir`` settings. diff --git a/doc/install/install.rst b/doc/install/install.rst index 7030c95642..7400d640fe 100644 --- a/doc/install/install.rst +++ b/doc/install/install.rst @@ -3,7 +3,7 @@ .. _Xcode: https://developer.apple.com/xcode/ .. _MacPorts: http://www.macports.org .. _Fink: http://www.finkproject.org -.. _Homebrew: http://mxcl.github.com/homebrew +.. _Homebrew: http://brew.sh .. _bro downloads page: http://bro.org/download/index.html .. _installing-bro: @@ -144,7 +144,7 @@ Bro releases are bundled into source packages for convenience and are available on the `bro downloads page`_. Alternatively, the latest Bro development version can be obtained through git repositories hosted at ``git.bro.org``. See our `git development documentation -`_ for comprehensive +`_ for comprehensive information on Bro's use of git revision control, but the short story for downloading the full source code experience for Bro via git is: diff --git a/doc/quickstart/index.rst b/doc/quickstart/index.rst index e8ead2cf01..85fdb88d7f 100644 --- a/doc/quickstart/index.rst +++ b/doc/quickstart/index.rst @@ -407,7 +407,7 @@ logging) and adds SSL certificate validation. You might notice that a script you load from the command line uses the ``@load`` directive in the Bro language to declare dependence on other scripts. This directive is similar to the ``#include`` of C/C++, except the semantics -are "load this script if it hasn't already been loaded". +are, "load this script if it hasn't already been loaded." .. note:: If one wants Bro to be able to load scripts that live outside the default directories in Bro's installation root, the ``BROPATH`` environment From 1842d324cb919c125cff727ff73655503f50bfb6 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 29 Jan 2014 15:34:24 -0600 Subject: [PATCH 051/254] Extend file analysis API to allow file ID caching, adapt HTTP to use it. This allows an analyzer to either provide file IDs associated with some file content or to cache a file ID that was already determined by script-layer logic so that subsequent calls to the file analysis interface can bypass costly detours through script-layer. This can yield a decent performance improvement for analyzers that are able to take advantage of it and deal with streaming content (like HTTP). --- src/analyzer/protocol/http/HTTP.cc | 16 ++++--- src/analyzer/protocol/http/HTTP.h | 1 + src/file_analysis/Manager.cc | 67 +++++++++++++++++++----------- src/file_analysis/Manager.h | 51 +++++++++++++++++++---- 4 files changed, 95 insertions(+), 40 deletions(-) diff --git a/src/analyzer/protocol/http/HTTP.cc b/src/analyzer/protocol/http/HTTP.cc index ffdcad226f..f9b9496992 100644 --- a/src/analyzer/protocol/http/HTTP.cc +++ b/src/analyzer/protocol/http/HTTP.cc @@ -242,10 +242,11 @@ int HTTP_Entity::Undelivered(int64_t len) if ( end_of_data && in_header ) return 0; - file_mgr->Gap(body_length, len, + cached_file_id = file_mgr->Gap(body_length, len, http_message->MyHTTP_Analyzer()->GetAnalyzerTag(), http_message->MyHTTP_Analyzer()->Conn(), - http_message->IsOrig()); + http_message->IsOrig(), + cached_file_id); if ( chunked_transfer_state != NON_CHUNKED_TRANSFER ) { @@ -314,15 +315,18 @@ void HTTP_Entity::SubmitData(int len, const char* buf) else { if ( send_size && content_length > 0 ) - file_mgr->SetSize(content_length, + cached_file_id = file_mgr->SetSize(content_length, http_message->MyHTTP_Analyzer()->GetAnalyzerTag(), http_message->MyHTTP_Analyzer()->Conn(), - http_message->IsOrig()); + http_message->IsOrig(), + cached_file_id); - file_mgr->DataIn(reinterpret_cast(buf), len, + cached_file_id = file_mgr->DataIn(reinterpret_cast(buf), + len, http_message->MyHTTP_Analyzer()->GetAnalyzerTag(), http_message->MyHTTP_Analyzer()->Conn(), - http_message->IsOrig()); + http_message->IsOrig(), + cached_file_id); } send_size = false; diff --git a/src/analyzer/protocol/http/HTTP.h b/src/analyzer/protocol/http/HTTP.h index 8339e48e3b..9951fa461b 100644 --- a/src/analyzer/protocol/http/HTTP.h +++ b/src/analyzer/protocol/http/HTTP.h @@ -64,6 +64,7 @@ protected: uint64_t offset; int64_t instance_length; // total length indicated by content-range bool send_size; // whether to send size indication to FAF + std::string cached_file_id; MIME_Entity* NewChildEntity() { return new HTTP_Entity(http_message, this, 1); } diff --git a/src/file_analysis/Manager.cc b/src/file_analysis/Manager.cc index 0337dbb098..56192e5bf4 100644 --- a/src/file_analysis/Manager.cc +++ b/src/file_analysis/Manager.cc @@ -75,36 +75,47 @@ void Manager::SetHandle(const string& handle) current_file_id = HashHandle(handle); } -void Manager::DataIn(const u_char* data, uint64 len, uint64 offset, - analyzer::Tag tag, Connection* conn, bool is_orig) +string Manager::DataIn(const u_char* data, uint64 len, uint64 offset, + analyzer::Tag tag, Connection* conn, bool is_orig, + const string& cached_id) { - GetFileHandle(tag, conn, is_orig); - File* file = GetFile(current_file_id, conn, tag, is_orig); + string id = cached_id.empty() ? GetFileID(tag, conn, is_orig) : cached_id; + File* file = GetFile(id, conn, tag, is_orig); if ( ! file ) - return; + return ""; file->DataIn(data, len, offset); if ( file->IsComplete() ) + { RemoveFile(file->GetID()); + return ""; + } + + return id; } -void Manager::DataIn(const u_char* data, uint64 len, analyzer::Tag tag, - Connection* conn, bool is_orig) +string Manager::DataIn(const u_char* data, uint64 len, analyzer::Tag tag, + Connection* conn, bool is_orig, const string& cached_id) { - GetFileHandle(tag, conn, is_orig); + string id = cached_id.empty() ? GetFileID(tag, conn, is_orig) : cached_id; // Sequential data input shouldn't be going over multiple conns, so don't // do the check to update connection set. - File* file = GetFile(current_file_id, conn, tag, is_orig, false); + File* file = GetFile(id, conn, tag, is_orig, false); if ( ! file ) - return; + return ""; file->DataIn(data, len); if ( file->IsComplete() ) + { RemoveFile(file->GetID()); + return ""; + } + + return id; } void Manager::DataIn(const u_char* data, uint64 len, const string& file_id, @@ -133,8 +144,7 @@ void Manager::EndOfFile(analyzer::Tag tag, Connection* conn) void Manager::EndOfFile(analyzer::Tag tag, Connection* conn, bool is_orig) { // Don't need to create a file if we're just going to remove it right away. - GetFileHandle(tag, conn, is_orig); - RemoveFile(current_file_id); + RemoveFile(GetFileID(tag, conn, is_orig)); } void Manager::EndOfFile(const string& file_id) @@ -142,31 +152,37 @@ void Manager::EndOfFile(const string& file_id) RemoveFile(file_id); } -void Manager::Gap(uint64 offset, uint64 len, analyzer::Tag tag, - Connection* conn, bool is_orig) +string Manager::Gap(uint64 offset, uint64 len, analyzer::Tag tag, + Connection* conn, bool is_orig, const string& cached_id) { - GetFileHandle(tag, conn, is_orig); - File* file = GetFile(current_file_id, conn, tag, is_orig); + string id = cached_id.empty() ? GetFileID(tag, conn, is_orig) : cached_id; + File* file = GetFile(id, conn, tag, is_orig); if ( ! file ) - return; + return ""; file->Gap(offset, len); + return id; } -void Manager::SetSize(uint64 size, analyzer::Tag tag, Connection* conn, - bool is_orig) +string Manager::SetSize(uint64 size, analyzer::Tag tag, Connection* conn, + bool is_orig, const string& cached_id) { - GetFileHandle(tag, conn, is_orig); - File* file = GetFile(current_file_id, conn, tag, is_orig); + string id = cached_id.empty() ? GetFileID(tag, conn, is_orig) : cached_id; + File* file = GetFile(id, conn, tag, is_orig); if ( ! file ) - return; + return ""; file->SetTotalBytes(size); if ( file->IsComplete() ) + { RemoveFile(file->GetID()); + return ""; + } + + return id; } bool Manager::SetTimeoutInterval(const string& file_id, double interval) const @@ -317,15 +333,15 @@ bool Manager::IsIgnored(const string& file_id) return ignored.find(file_id) != ignored.end(); } -void Manager::GetFileHandle(analyzer::Tag tag, Connection* c, bool is_orig) +string Manager::GetFileID(analyzer::Tag tag, Connection* c, bool is_orig) { current_file_id.clear(); if ( IsDisabled(tag) ) - return; + return ""; if ( ! get_file_handle ) - return; + return ""; EnumVal* tagval = tag.AsEnumVal(); Ref(tagval); @@ -337,6 +353,7 @@ void Manager::GetFileHandle(analyzer::Tag tag, Connection* c, bool is_orig) mgr.QueueEvent(get_file_handle, vl); mgr.Drain(); // need file handle immediately so we don't have to buffer data + return current_file_id; } bool Manager::IsDisabled(analyzer::Tag tag) diff --git a/src/file_analysis/Manager.h b/src/file_analysis/Manager.h index cf73c6b52d..ce8aa6b7d7 100644 --- a/src/file_analysis/Manager.h +++ b/src/file_analysis/Manager.h @@ -82,9 +82,17 @@ public: * @param conn network connection over which the file data is transferred. * @param is_orig true if the file is being sent from connection originator * or false if is being sent in the opposite direction. + * @param cached_file_id may be set to a previous return value in order to + * bypass costly file handle lookups. + * @return a unique file ID string which, in certain contexts, may be + * cached and passed back in to a subsequent function call in order + * to avoid costly file handle lookups (which have to go through + * the \c get_file_handle script-layer event). An empty string + * indicates the associate file is not going to be analyzed further. */ - void DataIn(const u_char* data, uint64 len, uint64 offset, - analyzer::Tag tag, Connection* conn, bool is_orig); + std::string DataIn(const u_char* data, uint64 len, uint64 offset, + analyzer::Tag tag, Connection* conn, bool is_orig, + const std::string& cached_file_id = ""); /** * Pass in sequential file data. @@ -94,9 +102,17 @@ public: * @param conn network connection over which the file data is transferred. * @param is_orig true if the file is being sent from connection originator * or false if is being sent in the opposite direction. + * @param cached_file_id may be set to a previous return value in order to + * bypass costly file handle lookups. + * @return a unique file ID string which, in certain contexts, may be + * cached and passed back in to a subsequent function call in order + * to avoid costly file handle lookups (which have to go through + * the \c get_file_handle script-layer event). An empty string + * indicates the associate file is not going to be analyzed further. */ - void DataIn(const u_char* data, uint64 len, analyzer::Tag tag, - Connection* conn, bool is_orig); + std::string DataIn(const u_char* data, uint64 len, analyzer::Tag tag, + Connection* conn, bool is_orig, + const std::string& cached_file_id = ""); /** * Pass in sequential file data from external source (e.g. input framework). @@ -140,9 +156,17 @@ public: * @param conn network connection over which the file data is transferred. * @param is_orig true if the file is being sent from connection originator * or false if is being sent in the opposite direction. + * @param cached_file_id may be set to a previous return value in order to + * bypass costly file handle lookups. + * @return a unique file ID string which, in certain contexts, may be + * cached and passed back in to a subsequent function call in order + * to avoid costly file handle lookups (which have to go through + * the \c get_file_handle script-layer event). An empty string + * indicates the associate file is not going to be analyzed further. */ - void Gap(uint64 offset, uint64 len, analyzer::Tag tag, Connection* conn, - bool is_orig); + std::string Gap(uint64 offset, uint64 len, analyzer::Tag tag, + Connection* conn, bool is_orig, + const std::string& cached_file_id = ""); /** * Provide the expected number of bytes that comprise a file. @@ -151,9 +175,16 @@ public: * @param conn network connection over which the file data is transferred. * @param is_orig true if the file is being sent from connection originator * or false if is being sent in the opposite direction. + * @param cached_file_id may be set to a previous return value in order to + * bypass costly file handle lookups. + * @return a unique file ID string which, in certain contexts, may be + * cached and passed back in to a subsequent function call in order + * to avoid costly file handle lookups (which have to go through + * the \c get_file_handle script-layer event). An empty string + * indicates the associate file is not going to be analyzed further. */ - void SetSize(uint64 size, analyzer::Tag tag, Connection* conn, - bool is_orig); + std::string SetSize(uint64 size, analyzer::Tag tag, Connection* conn, + bool is_orig, const std::string& cached_file_id = ""); /** * Starts ignoring a file, which will finally be removed from internal @@ -283,8 +314,10 @@ protected: * @param conn network connection over which the file is transferred. * @param is_orig true if the file is being sent from connection originator * or false if is being sent in the opposite direction. + * @return #current_file_id, which is a hash of a unique file handle string + * set by a \c get_file_handle event handler. */ - void GetFileHandle(analyzer::Tag tag, Connection* c, bool is_orig); + std::string GetFileID(analyzer::Tag tag, Connection* c, bool is_orig); /** * Check if analysis is available for files transferred over a given From 2b84af5b80fc943c84a5675ec9cb0975fa35952f Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 29 Jan 2014 17:11:20 -0600 Subject: [PATCH 052/254] Revert use of HTTP file ID caching for gaps range request content. Just an oversight on my part, this makes the use of file ID caching consistent between the uses of the DataIn and Gap interfaces. --- src/analyzer/protocol/http/HTTP.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/analyzer/protocol/http/HTTP.cc b/src/analyzer/protocol/http/HTTP.cc index f9b9496992..3e74ca645c 100644 --- a/src/analyzer/protocol/http/HTTP.cc +++ b/src/analyzer/protocol/http/HTTP.cc @@ -242,11 +242,17 @@ int HTTP_Entity::Undelivered(int64_t len) if ( end_of_data && in_header ) return 0; - cached_file_id = file_mgr->Gap(body_length, len, - http_message->MyHTTP_Analyzer()->GetAnalyzerTag(), - http_message->MyHTTP_Analyzer()->Conn(), - http_message->IsOrig(), - cached_file_id); + if ( is_partial_content ) + file_mgr->Gap(body_length, len, + http_message->MyHTTP_Analyzer()->GetAnalyzerTag(), + http_message->MyHTTP_Analyzer()->Conn(), + http_message->IsOrig()); + else + cached_file_id = file_mgr->Gap(body_length, len, + http_message->MyHTTP_Analyzer()->GetAnalyzerTag(), + http_message->MyHTTP_Analyzer()->Conn(), + http_message->IsOrig(), + cached_file_id); if ( chunked_transfer_state != NON_CHUNKED_TRANSFER ) { From c7cacb56b8d0efaf79d03466563025b43d12ba74 Mon Sep 17 00:00:00 2001 From: Jeannette Dopheide Date: Thu, 30 Jan 2014 13:13:26 -0600 Subject: [PATCH 053/254] Updates to Bro IDS documentation --- doc/broids/index.rst | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/doc/broids/index.rst b/doc/broids/index.rst index 46e0d6ded6..d401dbcf34 100644 --- a/doc/broids/index.rst +++ b/doc/broids/index.rst @@ -16,18 +16,18 @@ In the following sections, we present a few examples of common uses of Bro as an IDS. ------------------------------------------------ -Detecting an FTP Bruteforce attack and notifying +Detecting an FTP Brute-force Attack and Notifying ------------------------------------------------ -For the purpose of this exercise, we define FTP bruteforcing as too many +For the purpose of this exercise, we define FTP brute-forcing as too many rejected usernames and passwords occurring from a single address. We -start by defining a threshold for the number of attempts and a -monitoring interval in minutes as well as a new notice type. +start by defining a threshold for the number of attempts, a monitoring +interval (in minutes), and a new notice type. .. btest-include:: ${BRO_SRC_ROOT}/scripts/policy/protocols/ftp/detect-bruteforcing.bro :lines: 9-25 -Now, using the ftp_reply event, we check for error codes from the `500 +Using the ftp_reply event, we check for error codes from the `500 series `_ for the "USER" and "PASS" commands, representing rejected usernames or passwords. For this, we can use the :bro:see:`FTP::parse_ftp_reply_code` @@ -38,9 +38,9 @@ function to break down the reply code and check if the first digit is a .. btest-include:: ${BRO_SRC_ROOT}/scripts/policy/protocols/ftp/detect-bruteforcing.bro :lines: 52-60 -Next, we use the SumStats framework to raise a notice of the attack of -the attack when the number of failed attempts exceeds the specified -threshold during the measuring interval. +Next, we use the SumStats framework to raise a notice of the attack when +the number of failed attempts exceeds the specified threshold during the +measuring interval. .. btest-include:: ${BRO_SRC_ROOT}/scripts/policy/protocols/ftp/detect-bruteforcing.bro :lines: 28-50 @@ -56,14 +56,14 @@ Below is the final code for our script. As a final note, the :doc:`detect-bruteforcing.bro ` script above is -include with Bro out of the box, so you only need to load it at startup -to instruct Bro to detect and notify of FTP bruteforce attacks. +included with Bro out of the box. Use this feature by loading this script +during startup. ------------- Other Attacks ------------- -Detecting SQL Injection attacks +Detecting SQL Injection Attacks ------------------------------- Checking files against known malware hashes @@ -76,5 +76,4 @@ list of known malware hashes. Bro simplifies this task by offering a :doc:`detect-MHR.bro ` script that creates and compares hashes against the `Malware Hash Registry `_ maintained by Team -Cymru. You only need to load this script along with your other scripts -at startup time. +Cymru. Use this feature by loading this script during startup. From 2e2cb0ffc9e85cf163e0488104fc62238a50e4dc Mon Sep 17 00:00:00 2001 From: Jeannette Dopheide Date: Thu, 30 Jan 2014 13:22:25 -0600 Subject: [PATCH 054/254] Updates to Logs and Cluster documentation --- doc/cluster/index.rst | 127 +++++++++++++++++++++++++++++++++++------- doc/logs/index.rst | 51 ++++++++--------- 2 files changed, 133 insertions(+), 45 deletions(-) diff --git a/doc/cluster/index.rst b/doc/cluster/index.rst index 6de70d38cc..c4df063db5 100644 --- a/doc/cluster/index.rst +++ b/doc/cluster/index.rst @@ -6,7 +6,13 @@ Setting up a Bro Cluster Intro ------ -Bro is not multithreaded, so once the limitations of a single processor core are reached, the only option currently is to spread the workload across many cores or even many physical computers. The cluster deployment scenario for Bro is the current solution to build these larger systems. The accompanying tools and scripts provide the structure to easily manage many Bro processes examining packets and doing correlation activities but acting as a singular, cohesive entity. +Bro is not multithreaded, so once the limitations of a single processor core +are reached the only option currently is to spread the workload across many +cores, or even many physical computers. The cluster deployment scenario for +Bro is the current solution to build these larger systems. The accompanying +tools and scripts provide the structure to easily manage many Bro processes +examining packets and doing correlation activities but acting as a singular, +cohesive entity. Architecture --------------- @@ -17,42 +23,98 @@ The figure below illustrates the main components of a Bro cluster. Tap *** -This is a mechanism that splits the packet stream in order to make a copy -available for inspection. Examples include the monitoring port on a switch and -an optical splitter for fiber networks. +The tap is a mechanism that splits the packet stream in order to make a copy +available for inspection. Examples include the monitoring port on a switch +and an optical splitter on fiber networks. Frontend ******** -This is a discrete hardware device or on-host technique that will split your traffic into many streams or flows. The Bro binary does not do this job. There are numerous ways to accomplish this task, some of which are described below in `Frontend Options`_. +The frontend is a discrete hardware device or on-host technique that splits +traffic into many streams or flows. The Bro binary does not do this job. +There are numerous ways to accomplish this task, some of which are described +below in `Frontend Options`_. Manager ******* -This is a Bro process which has two primary jobs. It receives log messages and notices from the rest of the nodes in the cluster using the Bro communications protocol. The result is that you will end up with single logs for each log instead of many discrete logs that you have to later combine in some manner with post processing. The manager also takes the opportunity to de-duplicate notices and it has the ability to do so since it’s acting as the choke point for notices and how notices might be processed into actions such as emailing, paging, or blocking. +The manager is a Bro process that has two primary jobs. It receives log +messages and notices from the rest of the nodes in the cluster using the Bro +communications protocol. The result is a single log instead of many +discrete logs that you have to combine in some manner with post-processing. +The manager also takes the opportunity to de-duplicate notices, and it has the +ability to do so since it’s acting as the choke point for notices and how notices +might be processed into actions (e.g., emailing, paging, or blocking). -The manager process is started first by BroControl and it only opens it’s designated port and waits for connections, it doesn’t initiate any connections to the rest of the cluster. Once the workers are started and connect to the manager, logs and notices will start arriving to the manager process from the workers. +The manager process is started first by BroControl and it only opens its +designated port and waits for connections, it doesn’t initiate any +connections to the rest of the cluster. Once the workers are started and +connect to the manager, logs and notices will start arriving to the manager +process from the workers. Proxy ***** -This is a Bro process which manages synchronized state. Variables can be synchronized across connected Bro processes automatically in Bro and proxies will help the workers by alleviating the need for all of the workers to connect directly to each other. +The proxy is a Bro process that manages synchronized state. Variables can +be synchronized across connected Bro processes automatically. Proxies help +the workers by alleviating the need for all of the workers to connect +directly to each other. -Examples of synchronized state from the scripts that ship with Bro are things such as the full list of “known” hosts and services which are hosts or services which have been detected as performing full TCP handshakes or an analyzed protocol has been found on the connection. If worker A detects host 1.2.3.4 as an active host, it would be beneficial for worker B to know that as well so worker A shares that information as an insertion to a set which travels to the cluster’s proxy and the proxy then sends that same set insertion to worker B. The result is that worker A and worker B have shared knowledge about host and services that are active on the network being monitored. +Examples of synchronized state from the scripts that ship with Bro include +the full list of “known” hosts and services (which are hosts or services +identified as performing full TCP handshakes) or an analyzed protocol has been +found on the connection. If worker A detects host 1.2.3.4 as an active host, +it would be beneficial for worker B to know that as well. So worker A shares +that information as an insertion to a set + which travels to the cluster’s +proxy and the proxy sends that same set insertion to worker B. The result +is that worker A and worker B have shared knowledge about host and services +that are active on the network being monitored. -The proxy model extends to having multiple proxies as well if necessary for performance reasons, it only adds one additional step for the Bro processes. Each proxy connects to another proxy in a ring and the workers are shared between them as evenly as possible. When a proxy receives some new bit of state, it will share that with it’s proxy which is then shared around the ring of proxies and down to all of the workers. From a practical standpoint, there are no rules of thumb established yet for the number of proxies necessary for the number of workers they are serving. Best is to start with a single proxy and add more if communication performance problems are found. +The proxy model extends to having multiple proxies when necessary for +performance reasons. It only adds one additional step for the Bro processes. +Each proxy connects to another proxy in a ring and the workers are shared +between them as evenly as possible. When a proxy receives some new bit of +state it will share that with its proxy, which is then shared around the +ring of proxies, and down to all of the workers. From a practical standpoint, +there are no rules of thumb established for the number of proxies +necessary for the number of workers they are serving. It is best to start +with a single proxy and add more if communication performance problems are +found. -Bro processes acting as proxies don’t tend to be extremely intense to CPU or memory and users frequently run proxy processes on the same physical host as the manager. +Bro processes acting as proxies don’t tend to be extremely hard on CPU +or memory and users frequently run proxy processes on the same physical +host as the manager. Worker ****** -This is the Bro process that sniffs network traffic and does protocol analysis on the reassembled traffic streams. Most of the work of an active cluster takes place on the workers and as such, the workers typically represent the bulk of the Bro processes that are running in a cluster. The fastest memory and CPU core speed you can afford is best here since all of the protocol parsing and most analysis will take place here. There are no particular requirements for the disks in workers since almost all logging is done remotely to the manager and very little is normally written to disk. +The worker is the Bro process that sniffs network traffic and does protocol +analysis on the reassembled traffic streams. Most of the work of an active +cluster takes place on the workers and as such, the workers typically +represent the bulk of the Bro processes that are running in a cluster. +The fastest memory and CPU core speed you can afford is recommended +since all of the protocol parsing and most analysis will take place here. +There are no particular requirements for the disks in workers since almost all +logging is done remotely to the manager, and normally very little is written +to disk. -The rule of thumb we have followed recently is to allocate approximately 1 core for every 80Mbps of traffic that is being analyzed, however this estimate could be extremely traffic mix specific. It has generally worked for mixed traffic with many users and servers. For example, if your traffic peaks around 2Gbps (combined) and you want to handle traffic at peak load, you may want to have 26 cores available (2048 / 80 == 25.6). If the 80Mbps estimate works for your traffic, this could be handled by 3 physical hosts dedicated to being workers with each one containing dual 6-core processors. +The rule of thumb we have followed recently is to allocate approximately 1 +core for every 80Mbps of traffic that is being analyzed. However, this +estimate could be extremely traffic mix-specific. It has generally worked +for mixed traffic with many users and servers. For example, if your traffic +peaks around 2Gbps (combined) and you want to handle traffic at peak load, +you may want to have 26 cores available (2048 / 80 == 25.6). If the 80Mbps +estimate works for your traffic, this could be handled by 3 physical hosts +dedicated to being workers with each one containing dual 6-core processors. -Once a flow based load balancer is put into place this model is extremely easy to scale as well so it’s recommended that you guess at the amount of hardware you will need to fully analyze your traffic. If it turns out that you need more, it’s relatively easy to increase the size of the cluster in most cases. +Once a flow-based load balancer is put into place this model is extremely +easy to scale. It is recommended that you estimate the amount of +hardware you will need to fully analyze your traffic. If more is needed it’s +relatively easy to increase the size of the cluster in most cases. Frontend Options ---------------- -There are many options for setting up a frontend flow distributor and in many cases it may even be beneficial to do multiple stages of flow distribution on the network and on the host. +There are many options for setting up a frontend flow distributor. In many +cases it is beneficial to do multiple stages of flow distribution +on the network and on the host. Discrete hardware flow balancers ******************************** @@ -60,12 +122,24 @@ Discrete hardware flow balancers cPacket ^^^^^^^ -If you are monitoring one or more 10G physical interfaces, the recommended solution is to use either a cFlow or cVu device from cPacket because they are currently being used very successfully at a number of sites. These devices will perform layer-2 load balancing by rewriting the destination ethernet MAC address to cause each packet associated with a particular flow to have the same destination MAC. The packets can then be passed directly to a monitoring host where each worker has a BPF filter to limit its visibility to only that stream of flows or onward to a commodity switch to split the traffic out to multiple 1G interfaces for the workers. This can ultimately greatly reduce costs since workers can use relatively inexpensive 1G interfaces. +If you are monitoring one or more 10G physical interfaces, the recommended +solution is to use either a cFlow or cVu device from cPacket because they +are used successfully at a number of sites. These devices will perform +layer-2 load balancing by rewriting the destination Ethernet MAC address +to cause each packet associated with a particular flow to have the same +destination MAC. The packets can then be passed directly to a monitoring +host where each worker has a BPF filter to limit its visibility to only that +stream of flows, or onward to a commodity switch to split the traffic out to +multiple 1G interfaces for the workers. This greatly reduces +costs since workers can use relatively inexpensive 1G interfaces. OpenFlow Switches ^^^^^^^^^^^^^^^^^ -We are currently exploring the use of OpenFlow based switches to do flow based load balancing directly on the switch which can greatly reduce frontend costs for many users. This document will be updated when we have more information. +We are currently exploring the use of OpenFlow based switches to do flow-based +load balancing directly on the switch, which greatly reduces frontend +costs for many users. This document will be updated when we have more +information. On host flow balancing ********************** @@ -73,14 +147,27 @@ On host flow balancing PF_RING ^^^^^^^ -The PF_RING software for Linux has a “clustering” feature which will do flow based load balancing across a number of processes that are sniffing the same interface. This will allow you to easily take advantage of multiple cores in a single physical host because Bro’s main event loop is single threaded and can’t natively utilize all of the cores. More information about Bro with PF_RING can be found here: (someone want to write a quick Bro/PF_RING tutorial to link to here? document installing kernel module, libpcap wrapper, building Bro with the --with-pcap configure option) +The PF_RING software for Linux has a “clustering” feature which will do +flow-based load balancing across a number of processes that are sniffing the +same interface. This allows you to easily take advantage of multiple +cores in a single physical host because Bro’s main event loop is single +threaded and can’t natively utilize all of the cores. More information about +Bro with PF_RING can be found here: (someone want to write a quick Bro/PF_RING +tutorial to link to here? document installing kernel module, libpcap +wrapper, building Bro with the --with-pcap configure option) Netmap ^^^^^^ -FreeBSD has an in-progress project named Netmap which will enable flow based load balancing as well. When it becomes viable for real world use, this document will be updated. +FreeBSD has an in-progress project named Netmap which will enable flow-based +load balancing as well. When it becomes viable for real world use, this +document will be updated. Click! Software Router ^^^^^^^^^^^^^^^^^^^^^^ -Click! can be used for flow based load balancing with a simple configuration. (link to an example for the config). This solution is not recommended on Linux due to Bro’s PF_RING support and only as a last resort on other operating systems since it causes a lot of overhead due to context switching back and forth between kernel and userland several times per packet. +Click! can be used for flow based load balancing with a simple configuration. +(link to an example for the config). This solution is not recommended on +Linux due to Bro’s PF_RING support and only as a last resort on other +operating systems since it causes a lot of overhead due to context switching +back and forth between kernel and userland several times per packet. diff --git a/doc/logs/index.rst b/doc/logs/index.rst index b71546db72..ced9a78faa 100644 --- a/doc/logs/index.rst +++ b/doc/logs/index.rst @@ -24,17 +24,17 @@ Working with Log Files Generally, all of Bro's log files are produced by a corresponding script that defines their individual structure. However, as each log -file flows through the Logging Framework, there share a set of +file flows through the Logging Framework, they share a set of structural similarities. Without breaking into the scripting aspect of -Bro here, a bird's eye view of how the log files are produced would -progress as follows. The script's author defines the kinds of data, +Bro here, a bird's eye view of how the log files are produced +progresses as follows. The script's author defines the kinds of data, such as the originating IP address or the duration of a connection, which will make up the fields (i.e., columns) of the log file. The author then decides what network activity should generate a single log -file entry (i.e., one line); that could, e.g., be a connection having -been completed or an HTTP ``GET`` method being issued by an +file entry (i.e., one line). For example, this could be a connection +having been completed or an HTTP ``GET`` request being issued by an originator. When these behaviors are observed during operation, the -data is passed to the Logging Framework which, in turn, adds the entry +data is passed to the Logging Framework which adds the entry to the appropriate log file. As the fields of the log entries can be further customized by the @@ -57,7 +57,7 @@ data, the string ``(empty)`` as the indicator for an empty field and the ``-`` character as the indicator for a field that hasn't been set. The timestamp for when the file was created is included under ``#open``. The header then goes on to detail the fields being listed -in the file and the data types of those fields in ``#fields`` and +in the file and the data types of those fields, in ``#fields`` and ``#types``, respectively. These two entries are often the two most significant points of interest as they detail not only the field names but the data types used. When navigating through the different log @@ -66,12 +66,12 @@ definitions readily available saves the user some mental leg work. The field names are also a key resource for using the :ref:`bro-cut ` utility included with Bro, see below. -Next to the header follows the main content; in this example we see 7 +Next to the header follows the main content. In this example we see 7 connections with their key properties, such as originator and -responder IP addresses (note how Bro transparely handles both IPv4 and -IPv6), transport-layer ports, application-layer services - the -``service`` field is filled ias Bro determines a specific protocol to -be in use, independent of the connection's ports - payload size, and +responder IP addresses (note how Bro transparently handles both IPv4 and +IPv6), transport-layer ports, application-layer services ( - the +``service`` field is filled in as Bro determines a specific protocol to +be in use, independent of the connection's ports), payload size, and more. See :bro:type:`Conn::Info` for a description of all fields. In addition to ``conn.log``, Bro generates many further logs by @@ -87,8 +87,8 @@ default, including: A log of FTP session-level activity. ``files.log`` - Summaries of files transfered over the network. This information - is aggregrated from different protocols, including HTTP, FTP, and + Summaries of files transferred over the network. This information + is aggregated from different protocols, including HTTP, FTP, and SMTP. ``http.log`` @@ -106,7 +106,7 @@ default, including: ``weird.log`` A log of unexpected protocol-level activity. Whenever Bro's protocol analysis encounters a situation it would not expect - (e.g., an RFC violation) is logs it in this file. Note that in + (e.g., an RFC violation) it logs it in this file. Note that in practice, real-world networks tend to exhibit a large number of such "crud" that is usually not worth following up on. @@ -120,7 +120,7 @@ Using ``bro-cut`` The ``bro-cut`` utility can be used in place of other tools to build terminal commands that remain flexible and accurate independent of -possible changes to log file itself. It accomplishes this by parsing +possible changes to the log file itself. It accomplishes this by parsing the header in each file and allowing the user to refer to the specific columnar data available (in contrast to tools like ``awk`` that require the user to refer to fields referenced by their position). @@ -131,7 +131,7 @@ from a ``conn.log``: @TEST-EXEC: btest-rst-cmd -n 10 "cat conn.log | bro-cut id.orig_h id.orig_p id.resp_h duration" -The correspding ``awk`` command would look like this: +The corresponding ``awk`` command will look like this: .. btest:: using_bro @@ -185,8 +185,8 @@ Working with Timestamps ``bro-cut`` accepts the flag ``-d`` to convert the epoch time values in the log files to human-readable format. The following command -includes the human readable time stamp, the unique identifier and the -HTTP ``Host`` and HTTP ``URI`` as extracted from the ``http.log`` +includes the human readable time stamp, the unique identifier, the +HTTP ``Host``, and HTTP ``URI`` as extracted from the ``http.log`` file: .. btest:: using_bro @@ -218,7 +218,7 @@ See ``man strfime`` for more options for the format string. Using UIDs ---------- -While Bro can do signature based analysis, its primary focus is on +While Bro can do signature-based analysis, its primary focus is on behavioral detection which alters the practice of log review from "reactionary review" to a process a little more akin to a hunting trip. A common progression of review includes correlating a session @@ -254,12 +254,13 @@ network. ----------------------- Common Log Files ----------------------- -As a monitoring tool, Bro records a detailed view of the traffic inspected and the events generated in -a series of relevant log files. These files can later be reviewed for monitoring, auditing and troubleshooting -purposes. +As a monitoring tool, Bro records a detailed view of the traffic inspected +and the events generated in a series of relevant log files. These files can +later be reviewed for monitoring, auditing and troubleshooting purposes. -In this section we present a brief explanation of the most commonly used log files generated by Bro including links -to descriptions of some of the fields for each log type. +In this section we present a brief explanation of the most commonly used log +files generated by Bro including links to descriptions of some of the fields +for each log type. +-----------------+---------------------------------------+------------------------------+ | Log File | Description | Field Descriptions | From 121db68c302b82be9d83e64f6a12aba85d9ac243 Mon Sep 17 00:00:00 2001 From: Jeannette Dopheide Date: Thu, 30 Jan 2014 13:23:58 -0600 Subject: [PATCH 055/254] Updates to httpmonitor and mimestats documentation. --- doc/httpmonitor/index.rst | 21 ++++++++++----------- doc/mimestats/index.rst | 32 ++++++++++++++++---------------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/doc/httpmonitor/index.rst b/doc/httpmonitor/index.rst index f6b2f5e122..5a4f28ebfe 100644 --- a/doc/httpmonitor/index.rst +++ b/doc/httpmonitor/index.rst @@ -10,7 +10,7 @@ http.log file. This file can then be used for analysis and auditing purposes. In the sections below we briefly explain the structure of the http.log -file. Then, we show you how to perform basic HTTP traffic monitoring and +file, then we show you how to perform basic HTTP traffic monitoring and analysis tasks with Bro. Some of these ideas and techniques can later be applied to monitor different protocols in a similar way. @@ -40,11 +40,10 @@ request to the root of Bro website:: Network administrators and security engineers, for instance, can use the information in this log to understand the HTTP activity on the network -and troubleshoot network problems or search for anomalous activities. At -this point, we would like to stress out the fact that there is no just -one right way to perform analysis; it will depend on the expertise of -the person doing the analysis and the specific details of the task to -accomplish. +and troubleshoot network problems or search for anomalous activities. We must +stress that there is no single right way to perform an analysis. It will +depend on the expertise of the person performing the analysis and the +specific details of the task. For more information about how to handle the HTTP protocol in Bro, including a complete list of the fields available in http.log, go to @@ -58,15 +57,15 @@ Detecting a Proxy Server A proxy server is a device on your network configured to request a service on behalf of a third system; one of the most common examples is a Web proxy server. A client without Internet access connects to the -proxy and requests a Web page; the proxy then sends the request to the -actual Web server, receives the response and passes it to the original +proxy and requests a web page, the proxy sends the request to the web +server, which receives the response, and passes it to the original client. Proxies were conceived to help manage a network and provide better -encapsulation. By themselves, proxies are not a security threat, but a +encapsulation. Proxies by themselves are not a security threat, but a misconfigured or unauthorized proxy can allow others, either inside or -outside the network, to access any Web site and even conduct malicious -activities anonymously using the network resources. +outside the network, to access any web site and even conduct malicious +activities anonymously using the network's resources. What Proxy Server traffic looks like ------------------------------------- diff --git a/doc/mimestats/index.rst b/doc/mimestats/index.rst index df17f4872f..dd2e039e8a 100644 --- a/doc/mimestats/index.rst +++ b/doc/mimestats/index.rst @@ -6,19 +6,19 @@ MIME Type Statistics ==================== Files are constantly transmitted over HTTP on regular networks. These -files belong to a specific category (i.e., executable, text, image, -etc.) identified by a `Multipurpose Internet Mail Extension (MIME) +files belong to a specific category (e.g., executable, text, image) +identified by a `Multipurpose Internet Mail Extension (MIME) `_. Although MIME was originally developed to identify the type of non-text attachments on email, it is -also used by Web browser to identify the type of files transmitted and +also used by a web browser to identify the type of files transmitted and present them accordingly. -In this tutorial, we will show how to use the Sumstats Framework to -collect some statistics information based on MIME types, specifically +In this tutorial, we will demonstrate how to use the Sumstats Framework +to collect statistical information based on MIME types; specifically, the total number of occurrences, size in bytes, and number of unique -hosts transmitting files over HTTP per each type. For instructions about -extracting and creating a local copy of these files, visit :ref:`this -` tutorial instead. +hosts transmitting files over HTTP per each type. For instructions on +extracting and creating a local copy of these files, visit :ref:`this +tutorial `. ------------------------------------------------ MIME Statistics with Sumstats @@ -30,31 +30,31 @@ Observations, where the event is observed and fed into the framework. (ii) Reducers, where observations are collected and measured. (iii) Sumstats, where the main functionality is implemented. -So, we start by defining our observation along with a record to store -all statistics values and an observation interval. We are conducting our -observation on the :bro:see:`HTTP::log_http` event and we are interested -in the MIME type, size of the file ("response_body_len") and the +We start by defining our observation along with a record to store +all statistical values and an observation interval. We are conducting our +observation on the :bro:see:`HTTP::log_http` event and are interested +in the MIME type, size of the file ("response_body_len"), and the originator host ("orig_h"). We use the MIME type as our key and create observers for the other two values. .. btest-include:: ${DOC_ROOT}/mimestats/mimestats.bro :lines: 6-29, 54-64 -Next, we create the reducers. The first one will accumulate file sizes -and the second one will make sure we only store a host ID once. Below is +Next, we create the reducers. The first will accumulate file sizes +and the second will make sure we only store a host ID once. Below is the partial code from a :bro:see:`bro_init` handler. .. btest-include:: ${DOC_ROOT}/mimestats/mimestats.bro :lines: 34-37 In our final step, we create the SumStats where we check for the -observation interval and once it expires, we populate the record +observation interval. Once it expires, we populate the record (defined above) with all the relevant data and write it to a log. .. btest-include:: ${DOC_ROOT}/mimestats/mimestats.bro :lines: 38-51 -Putting everything together we end up with the following final code for +After putting the three pieces together we end up with the following final code for our script. .. btest-include:: ${DOC_ROOT}/mimestats/mimestats.bro From c61dfb19630a163ca306be275638b546cac5d6ad Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 30 Jan 2014 17:21:01 -0600 Subject: [PATCH 056/254] Rewrite DNS state tracking which matches queries and replies. The previous method of matching queries with replies was still unreliable in cases where the reply contains no answers. The new code also takes extra measures to avoid pending state growing too large in cases where the condition to match a query with a corresponding reply is never met, but yet DNS messages continue to be exchanged over the same connection 5-tuple (preventing cleanup of the pending state). --- scripts/base/protocols/dns/main.bro | 248 +++++++++++++-------- scripts/policy/protocols/dns/auth-addl.bro | 19 +- 2 files changed, 166 insertions(+), 101 deletions(-) diff --git a/scripts/base/protocols/dns/main.bro b/scripts/base/protocols/dns/main.bro index 0651e23ada..21a0711159 100644 --- a/scripts/base/protocols/dns/main.bro +++ b/scripts/base/protocols/dns/main.bro @@ -63,15 +63,17 @@ export { ## The DNS query was rejected by the server. rejected: bool &log &default=F; - ## This value indicates if this request/response pair is ready - ## to be logged. - ready: bool &default=F; ## The total number of resource records in a reply message's ## answer section. total_answers: count &optional; ## The total number of resource records in a reply message's ## answer, authority, and additional sections. total_replies: count &optional; + + ## Whether the full DNS query has been seen. + saw_query: bool &default=F; + ## Whether the full DNS reply has been seen. + saw_reply: bool &default=F; }; ## An event that can be handled to access the :bro:type:`DNS::Info` @@ -90,7 +92,7 @@ export { ## ans: The general information of a RR response. ## ## reply: The specific response information according to RR type/class. - global do_reply: event(c: connection, msg: dns_msg, ans: dns_answer, reply: string); + global do_reply: hook(c: connection, msg: dns_msg, ans: dns_answer, reply: string); ## A hook that is called whenever a session is being set. ## This can be used if additional initialization logic needs to happen @@ -103,17 +105,42 @@ export { ## is_query: Indicator for if this is being called for a query or a response. global set_session: hook(c: connection, msg: dns_msg, is_query: bool); + ## Yields a queue of :bro:see:`DNS::Info` objects for a given + ## DNS message query/transaction ID. + type PendingMessages: table[count] of Queue::Queue; + + ## Called when a pending DNS query has not been matched with a reply (or + ## vice versa) in a sufficent amount of time. + ## + ## pending: table of pending messages, indexed by transaction ID. + ## + ## id: the index of he element being expired. + ## + ## Returns: amount of time to delay expiration of the element. + global expire_pending_msg: function(pending: PendingMessages, id: count): interval; + + ## The amount of time that DNS queries or replies for a given + ## query/transaction ID are allowed to be queued while waiting for + ## a matching reply or query. + const pending_msg_expiry_interval = 2min &redef; + + ## Give up trying to match pending DNS queries or replies for a given + ## query/transaction ID once this number of unmatched queries or replies + ## is reached (this shouldn't happen unless either the DNS server/resolver + ## is broken, Bro is not seeing all the DNS traffic, or an AXFR query + ## response is ongoing). + const max_pending_msgs = 50 &redef; + ## A record type which tracks the status of DNS queries for a given ## :bro:type:`connection`. type State: record { ## Indexed by query id, returns Info record corresponding to - ## query/response which haven't completed yet. - pending: table[count] of Queue::Queue; + ## queries that haven't been matched with a response yet. + pending_queries: PendingMessages &read_expire=pending_msg_expiry_interval &expire_func=expire_pending_msg; - ## This is the list of DNS responses that have completed based - ## on the number of responses declared and the number received. - ## The contents of the set are transaction IDs. - finished_answers: set[count]; + ## Indexed by query id, returns Info record corresponding to + ## replies that haven't been matched with a query yet. + pending_replies: PendingMessages &read_expire=pending_msg_expiry_interval &expire_func=expire_pending_msg; }; } @@ -143,6 +170,51 @@ function new_session(c: connection, trans_id: count): Info return info; } +function log_unmatched_msgs_queue(q: Queue::Queue) + { + local infos: vector of Info; + Queue::get_vector(q, infos); + + for ( i in infos ) + Log::write(DNS::LOG, infos[i]); + } + +function log_unmatched_msgs(msgs: PendingMessages) + { + for ( trans_id in msgs ) + { + log_unmatched_msgs_queue(msgs[trans_id]); + delete msgs[trans_id]; + } + } + +function enqueue_new_msg(msgs: PendingMessages, id: count, msg: Info) + { + if ( id !in msgs ) + msgs[id] = Queue::init(); + else if ( Queue::len(msgs[id]) > max_pending_msgs ) + { + local info: Info = Queue::peek(msgs[id]); + event flow_weird("dns_unmatched_msg_quantity", info$id$orig_h, + info$id$resp_h); + log_unmatched_msgs_queue(msgs[id]); + # Throw away all unmatched on assumption they'll never be matched. + msgs[id] = Queue::init(); + } + + Queue::put(msgs[id], msg); + } + +function pop_msg(msgs: PendingMessages, id: count): Info + { + local rval: Info = Queue::get(msgs[id]); + + if ( Queue::len(msgs[id]) == 0 ) + delete msgs[id]; + + return rval; + } + hook set_session(c: connection, msg: dns_msg, is_query: bool) &priority=5 { if ( ! c?$dns_state ) @@ -151,34 +223,39 @@ hook set_session(c: connection, msg: dns_msg, is_query: bool) &priority=5 c$dns_state = state; } - if ( msg$id !in c$dns_state$pending ) - c$dns_state$pending[msg$id] = Queue::init(); - - local info: Info; - # If this is either a query or this is the reply but - # no Info records are in the queue (we missed the query?) - # we need to create an Info record and put it in the queue. if ( is_query ) { - info = new_session(c, msg$id); - Queue::put(c$dns_state$pending[msg$id], info); + if ( msg$id in c$dns_state$pending_replies && + Queue::len(c$dns_state$pending_replies[msg$id]) > 0 ) + { + # Match this DNS query w/ what's at head of pending reply queue. + c$dns = pop_msg(c$dns_state$pending_replies, msg$id); + } + else + { + # Create a new DNS session and put it in the query queue so + # we can wait for a matching reply. + c$dns = new_session(c, msg$id); + enqueue_new_msg(c$dns_state$pending_queries, msg$id, c$dns); + } } - else if ( Queue::len(c$dns_state$pending[msg$id]) == 0 ) - { - info = new_session(c, msg$id); - Queue::put(c$dns_state$pending[msg$id], info); - event conn_weird("dns_unmatched_reply", c, ""); - } - - if ( is_query ) - # If this is a query, assign the newly created info variable - # so that the world looks correct to anything else handling - # this query. - c$dns = info; else - # Peek at the next item in the queue for this trans_id and - # assign it to c$dns since this is a response. - c$dns = Queue::peek(c$dns_state$pending[msg$id]); + { + if ( msg$id in c$dns_state$pending_queries && + Queue::len(c$dns_state$pending_queries[msg$id]) > 0 ) + { + # Match this DNS reply w/ what's at head of pending query queue. + c$dns = pop_msg(c$dns_state$pending_queries, msg$id); + } + else + { + # Create a new DNS session and put it in the reply queue so + # we can wait for a matching query. + c$dns = new_session(c, msg$id); + event conn_weird("dns_unmatched_reply", c, ""); + enqueue_new_msg(c$dns_state$pending_replies, msg$id, c$dns); + } + } if ( ! is_query ) { @@ -188,19 +265,11 @@ hook set_session(c: connection, msg: dns_msg, is_query: bool) &priority=5 if ( ! c$dns?$total_answers ) c$dns$total_answers = msg$num_answers; - if ( c$dns?$total_replies && - c$dns$total_replies != msg$num_answers + msg$num_addl + msg$num_auth ) - { - event conn_weird("dns_changed_number_of_responses", c, - fmt("The declared number of responses changed from %d to %d", - c$dns$total_replies, - msg$num_answers + msg$num_addl + msg$num_auth)); - } - else - { - # Store the total number of responses expected from the first reply. + if ( ! c$dns?$total_replies ) c$dns$total_replies = msg$num_answers + msg$num_addl + msg$num_auth; - } + + if ( msg$rcode != 0 && msg$num_queries == 0 ) + c$dns$rejected = T; } } @@ -210,13 +279,10 @@ event dns_message(c: connection, is_orig: bool, msg: dns_msg, len: count) &prior # Currently only standard queries are tracked. return; - hook set_session(c, msg, is_orig); - - if ( msg$QR && msg$rcode != 0 && msg$num_queries == 0 ) - c$dns$rejected = T; + hook set_session(c, msg, ! msg$QR); } -event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=5 +hook DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=5 { if ( msg$opcode != 0 ) # Currently only standard queries are tracked. @@ -229,9 +295,6 @@ event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) if ( ans$answer_type == DNS_ANS ) { - if ( ! c?$dns ) - hook set_session(c, msg, F); - c$dns$AA = msg$AA; c$dns$RA = msg$RA; @@ -245,23 +308,25 @@ event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) c$dns$TTLs = vector(); c$dns$TTLs[|c$dns$TTLs|] = ans$TTL; } - - if ( c$dns?$answers && c$dns?$total_answers && - |c$dns$answers| == c$dns$total_answers ) - { - # Indicate this request/reply pair is ready to be logged. - c$dns$ready = T; - } } } -event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=-5 +event dns_end(c: connection, msg: dns_msg) &priority=5 { - if ( c?$dns && c$dns$ready ) + if ( ! c?$dns ) + return; + + if ( msg$QR ) + c$dns$saw_reply = T; + else + c$dns$saw_query = T; + } + +event dns_end(c: connection, msg: dns_msg) &priority=-5 + { + if ( c?$dns && c$dns$saw_reply && c$dns$saw_query ) { Log::write(DNS::LOG, c$dns); - # This record is logged and no longer pending. - Queue::get(c$dns_state$pending[c$dns$trans_id]); delete c$dns; } } @@ -291,63 +356,63 @@ event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qcla event dns_unknown_reply(c: connection, msg: dns_msg, ans: dns_answer) &priority=5 { - event DNS::do_reply(c, msg, ans, fmt("", ans$qtype)); + hook DNS::do_reply(c, msg, ans, fmt("", ans$qtype)); } event dns_A_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5 { - event DNS::do_reply(c, msg, ans, fmt("%s", a)); + hook DNS::do_reply(c, msg, ans, fmt("%s", a)); } event dns_TXT_reply(c: connection, msg: dns_msg, ans: dns_answer, str: string) &priority=5 { - event DNS::do_reply(c, msg, ans, str); + hook DNS::do_reply(c, msg, ans, str); } event dns_AAAA_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5 { - event DNS::do_reply(c, msg, ans, fmt("%s", a)); + hook DNS::do_reply(c, msg, ans, fmt("%s", a)); } event dns_A6_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5 { - event DNS::do_reply(c, msg, ans, fmt("%s", a)); + hook DNS::do_reply(c, msg, ans, fmt("%s", a)); } event dns_NS_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string) &priority=5 { - event DNS::do_reply(c, msg, ans, name); + hook DNS::do_reply(c, msg, ans, name); } event dns_CNAME_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string) &priority=5 { - event DNS::do_reply(c, msg, ans, name); + hook DNS::do_reply(c, msg, ans, name); } event dns_MX_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string, preference: count) &priority=5 { - event DNS::do_reply(c, msg, ans, name); + hook DNS::do_reply(c, msg, ans, name); } event dns_PTR_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string) &priority=5 { - event DNS::do_reply(c, msg, ans, name); + hook DNS::do_reply(c, msg, ans, name); } event dns_SOA_reply(c: connection, msg: dns_msg, ans: dns_answer, soa: dns_soa) &priority=5 { - event DNS::do_reply(c, msg, ans, soa$mname); + hook DNS::do_reply(c, msg, ans, soa$mname); } event dns_WKS_reply(c: connection, msg: dns_msg, ans: dns_answer) &priority=5 { - event DNS::do_reply(c, msg, ans, ""); + hook DNS::do_reply(c, msg, ans, ""); } event dns_SRV_reply(c: connection, msg: dns_msg, ans: dns_answer) &priority=5 { - event DNS::do_reply(c, msg, ans, ""); + hook DNS::do_reply(c, msg, ans, ""); } # TODO: figure out how to handle these @@ -377,16 +442,23 @@ event connection_state_remove(c: connection) &priority=-5 if ( ! c?$dns_state ) return; - # If Bro is expiring state, we should go ahead and log all unlogged - # request/response pairs now. - for ( trans_id in c$dns_state$pending ) - { - local infos: vector of Info; - Queue::get_vector(c$dns_state$pending[trans_id], infos); - for ( i in infos ) - { - Log::write(DNS::LOG, infos[i]); - } - } + # If Bro is expiring state, we should go ahead and log all unmatched + # queries and replies now. + log_unmatched_msgs(c$dns_state$pending_queries); + log_unmatched_msgs(c$dns_state$pending_replies); } +function expire_pending_msg(pending: PendingMessages, id: count): interval + { + local infos: vector of Info; + Queue::get_vector(pending[id], infos); + + for ( i in infos ) + { + Log::write(DNS::LOG, infos[i]); + event flow_weird("dns_unmatched_msg", infos[i]$id$orig_h, + infos[i]$id$resp_h); + } + + return 0sec; + } diff --git a/scripts/policy/protocols/dns/auth-addl.bro b/scripts/policy/protocols/dns/auth-addl.bro index bc97d529cd..a04cca37ab 100644 --- a/scripts/policy/protocols/dns/auth-addl.bro +++ b/scripts/policy/protocols/dns/auth-addl.bro @@ -19,17 +19,17 @@ export { }; } -event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=4 +hook DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=5 { if ( msg$opcode != 0 ) # Currently only standard queries are tracked. return; - # The "ready" flag will be set here. This causes the setting from the - # base script to be overridden since the base script will log immediately - # after all of the ANS replies have been seen. - c$dns$ready=F; - + if ( ! msg$QR ) + # This is weird: the inquirer must also be providing answers in + # the request, which is not what we want to track. + return; + if ( ans$answer_type == DNS_AUTH ) { if ( ! c$dns?$auth ) @@ -42,11 +42,4 @@ event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) c$dns$addl = set(); add c$dns$addl[reply]; } - - if ( c$dns?$answers && c$dns?$auth && c$dns?$addl && - c$dns$total_replies == |c$dns$answers| + |c$dns$auth| + |c$dns$addl| ) - { - # *Now* all replies desired have been seen. - c$dns$ready = T; - } } From cdf09b4acef5c4c0e03d8170f6ac12bc514b582d Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Fri, 31 Jan 2014 09:56:20 -0800 Subject: [PATCH 057/254] Updating submodule(s). [nomail] --- aux/btest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/btest b/aux/btest index 36b96eb9c1..23ff11bf0e 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit 36b96eb9c13d1011bbc8be3581fd0f1c0bd8de44 +Subproject commit 23ff11bf0edbad2c6f1acbeb3f9a029ff4b61785 From 0cb2a90da4aa1de49e3881b9471e69f862d62038 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 31 Jan 2014 17:04:58 -0600 Subject: [PATCH 058/254] Add script to detect filtered TCP traces, addresses BIT-1119. If reading a trace file w/ only TCP control packets, a warning is emitted to suggest the 'detect_filtered_traces' option if the user doesn't desire Bro to report missing TCP segments for such a trace file. --- scripts/base/init-default.bro | 1 + scripts/base/misc/find-filtered-trace.bro | 49 ++++++++++++++++++ .../canonified_loaded_scripts.log | 5 +- .../out1 | 1 + .../out2 | 0 .../btest/Traces/http/bro.org-filtered.pcap | Bin 0 -> 3934 bytes .../base/misc/find-filtered-trace.test | 4 ++ 7 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 scripts/base/misc/find-filtered-trace.bro create mode 100644 testing/btest/Baseline/scripts.base.misc.find-filtered-trace/out1 create mode 100644 testing/btest/Baseline/scripts.base.misc.find-filtered-trace/out2 create mode 100644 testing/btest/Traces/http/bro.org-filtered.pcap create mode 100644 testing/btest/scripts/base/misc/find-filtered-trace.test diff --git a/scripts/base/init-default.bro b/scripts/base/init-default.bro index d0120d930b..d87574f4e5 100644 --- a/scripts/base/init-default.bro +++ b/scripts/base/init-default.bro @@ -60,3 +60,4 @@ @load base/misc/find-checksum-offloading +@load base/misc/find-filtered-trace diff --git a/scripts/base/misc/find-filtered-trace.bro b/scripts/base/misc/find-filtered-trace.bro new file mode 100644 index 0000000000..a723b656a7 --- /dev/null +++ b/scripts/base/misc/find-filtered-trace.bro @@ -0,0 +1,49 @@ +##! Discovers trace files that contain TCP traffic consisting only of +##! control packets (e.g. it's been filtered to contain only SYN/FIN/RST +##! packets and no content). On finding such a trace, a warning is +##! emitted that suggests toggling the :bro:see:`detect_filtered_trace` +##! option may be desired if the user does not want Bro to report +##! missing TCP segments. + +module FilteredTraceDetection; + +export { + + ## Flag to enable filtered trace file detection and warning message. + global enable: bool = T &redef; +} + +global saw_tcp_conn_with_data: bool = F; +global saw_a_tcp_conn: bool = F; + +event connection_state_remove(c: connection) + { + if ( ! reading_traces() ) + return; + + if ( ! enable ) + return; + + if ( saw_tcp_conn_with_data ) + return; + + if ( ! is_tcp_port(c$id$orig_p) ) + return; + + saw_a_tcp_conn = T; + + if ( /[Dd]/ in c$history ) + saw_tcp_conn_with_data = T; + } + +event bro_done() + { + if ( ! enable ) + return; + + if ( ! saw_a_tcp_conn ) + return; + + if ( ! saw_tcp_conn_with_data ) + Reporter::warning("The analyzed trace file was determined to contain only TCP control packets, which may indicate it's been pre-filtered. By default, Bro reports the missing segments for this type of trace, but the 'detect_filtered_trace' option may be toggled if that's not desired."); + } diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 90145d94fb..76b3f3a596 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -3,7 +3,7 @@ #empty_field (empty) #unset_field - #path loaded_scripts -#open 2013-10-30-16-52-28 +#open 2014-01-31-22-54-38 #fields name #types string scripts/base/init-bare.bro @@ -220,5 +220,6 @@ scripts/base/init-default.bro scripts/base/files/unified2/__load__.bro scripts/base/files/unified2/main.bro scripts/base/misc/find-checksum-offloading.bro + scripts/base/misc/find-filtered-trace.bro scripts/policy/misc/loaded-scripts.bro -#close 2013-10-30-16-52-28 +#close 2014-01-31-22-54-38 diff --git a/testing/btest/Baseline/scripts.base.misc.find-filtered-trace/out1 b/testing/btest/Baseline/scripts.base.misc.find-filtered-trace/out1 new file mode 100644 index 0000000000..c2f791ba82 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.misc.find-filtered-trace/out1 @@ -0,0 +1 @@ +1389719059.311687 warning in /Users/jsiwek/Projects/bro/bro/scripts/base/misc/find-filtered-trace.bro, line 48: The analyzed trace file was determined to contain only TCP control packets, which may indicate it's been pre-filtered. By default, Bro reports the missing segments for this type of trace, but the 'detect_filtered_trace' option may be toggled if that's not desired. diff --git a/testing/btest/Baseline/scripts.base.misc.find-filtered-trace/out2 b/testing/btest/Baseline/scripts.base.misc.find-filtered-trace/out2 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testing/btest/Traces/http/bro.org-filtered.pcap b/testing/btest/Traces/http/bro.org-filtered.pcap new file mode 100644 index 0000000000000000000000000000000000000000..b25905079eec524262b750a53c96cf96364a9f72 GIT binary patch literal 3934 zcmaLae@vBC7zgn4z91k!#<*%KBwB%7`LR$EBWbd?G}Dpqzzy*-b89U_Cz?RTDsH%G zh-q$2Oq)YV1*J?-DKVq50e`s65rYuatZ>-GG}=rgdcNoMo(^00-0d=W|M=YRdCqg5 zbNQjQ;gHGvne!SOW6YpGjE!Ac=id)y%jkE!vsNRhwx+k&75J{U@CEH-m!N%%5M!bHmRs5c2+pFqTe#<1I|b zCpj@^n2~%S5Gr(LcgIVhUW{Jev;K1Ark(7%IMulS(ztOx|!X%adaBe zAmvEGxRh0Rj+Bt^P1earmO&0XB;`5GZa0?nJMx98zU5f@eBYH_`XuE1^HPpyc3sPf zCPyxQXPmrG%{(|=C#MWRE}bCd1ZKCCeE*&!Kl8x1d|-x74p;}deyfy|m|fxe^>;^J zJ>*-?U0`UsVHJIDM!^27N;f1~jq?oB@1h&B!-Y&gY0tX#Ry4Qz6)V9yooG-EN@1l% zsuoMr=9 za3+Ff=khbr*+$v6+Y!}$>ykvGXD92FrO!jjZcDE(TkmqK zOtIpulY9LJM=uq_y6}o>ZNF}4DjnU6)m6sI)nOJ>Cd#&g=ZY7rvwzYlG4)V(WlM$M zJC}+n747{gZ|Du7JPh{Jb+(tUt5jJRow)lW?M7w=vheZDmxdbEh4^XKb!0sfg;mN# z{3gh(Anze|?d1(3(eZ`q zK;LUk^px?nzOAg)wz}3Dq!(f$Bp-ApLKs1bNIc9l+mGT z$|0|l5^~vPog5kq`DmMzS24TQb>kQW$Wf1vlW9$2{g5wr>g0|skZ-*yZOE}VVW zk=-;+{`;mfG)}JX(#d6YkdrMbuV(gh)f@QvLgt8n?_1OoEtiS4eFVBu%`4mRyft(yD!A|KDs@haVtx)XkO$;d7E#Vn2ie?(Gz&V+WT>c zW;TX*Wl&Gl#LI5uQ|+cn-lKLzX6+DtgP26h2>lo0`;P881Eu#xsfg1sk5)*D(t?I} z3uXUdol%LU zMNGR|>T#~zZxYJIPj$+`LMRtor6SI9Gj$PHUOOw4nifqTx;;INl&UyoztM*#_2GH! zcQwCju;17z<6EuuBe!NN7W&YnK1_j?R0RhwSjl>;ms_!lg|lYTSxbVIa$HEl^60HA o+=@{w%oCI5Ngb@Y->BAhy+vn<>h*+TVV;;YPyT?l*yULN0OWAI4*&oF literal 0 HcmV?d00001 diff --git a/testing/btest/scripts/base/misc/find-filtered-trace.test b/testing/btest/scripts/base/misc/find-filtered-trace.test new file mode 100644 index 0000000000..05b603ac92 --- /dev/null +++ b/testing/btest/scripts/base/misc/find-filtered-trace.test @@ -0,0 +1,4 @@ +# @TEST-EXEC: bro -r $TRACES/http/bro.org-filtered.pcap >out1 2>&1 +# @TEST-EXEC: bro -r $TRACES/http/bro.org-filtered.pcap "FilteredTraceDetection::enable=F" >out2 2>&1 +# @TEST-EXEC: TEST_DIFF_CANOIFIER=$SCRIPTS/diff-remove-abspath btest-diff out1 +# @TEST-EXEC: btest-diff out2 From ab4508486e2337ba9eccf123343f6133530d6813 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Mon, 3 Feb 2014 16:54:48 -0600 Subject: [PATCH 059/254] Minor unified2 script documentation fix. --- scripts/base/files/unified2/main.bro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/base/files/unified2/main.bro b/scripts/base/files/unified2/main.bro index 870f9335ae..2f6ae79f4f 100644 --- a/scripts/base/files/unified2/main.bro +++ b/scripts/base/files/unified2/main.bro @@ -7,10 +7,10 @@ module Unified2; export { redef enum Log::ID += { LOG }; - ## Directory to watch for Unified2 files. + ## File to watch for Unified2 files. const watch_file = "" &redef; - ## File to watch for Unified2 records. + ## Directory to watch for Unified2 records. const watch_dir = "" &redef; ## The sid-msg.map file you would like to use for your alerts. From 4b63b3090165b59863356a9e4ee228c2f1ac5809 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Wed, 5 Feb 2014 10:01:51 -0800 Subject: [PATCH 060/254] Fix x509-extension test sometimes failing. For some fields, the format apparently is not consistens over OpenSSL versions. For the test, we simply skip those. --- .../scripts.base.protocols.ssl.x509_extensions/.stdout | 2 -- .../btest/scripts/base/protocols/ssl/x509_extensions.test | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/testing/btest/Baseline/scripts.base.protocols.ssl.x509_extensions/.stdout b/testing/btest/Baseline/scripts.base.protocols.ssl.x509_extensions/.stdout index 3f9c8661bf..c33135d3f8 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ssl.x509_extensions/.stdout +++ b/testing/btest/Baseline/scripts.base.protocols.ssl.x509_extensions/.stdout @@ -4,7 +4,6 @@ [name=X509v3 Basic Constraints, short_name=basicConstraints, oid=2.5.29.19, critical=T, value=CA:FALSE] [name=X509v3 Extended Key Usage, short_name=extendedKeyUsage, oid=2.5.29.37, critical=F, value=TLS Web Server Authentication, TLS Web Client Authentication] [name=X509v3 Certificate Policies, short_name=certificatePolicies, oid=2.5.29.32, critical=F, value=Policy: 1.3.6.1.4.1.6449.1.2.1.3.4^J CPS: https://secure.comodo.com/CPS^J] -[name=X509v3 CRL Distribution Points, short_name=crlDistributionPoints, oid=2.5.29.31, critical=F, value=^JFull Name:^J URI:http://crl.comodoca.com/COMODOHigh-AssuranceSecureServerCA.crl^J] [name=Authority Information Access, short_name=authorityInfoAccess, oid=1.3.6.1.5.5.7.1.1, critical=F, value=CA Issuers - URI:http://crt.comodoca.com/COMODOHigh-AssuranceSecureServerCA.crt^JOCSP - URI:http://ocsp.comodoca.com^J] [name=X509v3 Subject Alternative Name, short_name=subjectAltName, oid=2.5.29.17, critical=F, value=DNS:*.taleo.net, DNS:taleo.net] [name=X509v3 Authority Key Identifier, short_name=authorityKeyIdentifier, oid=2.5.29.35, critical=F, value=keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A^J] @@ -12,7 +11,6 @@ [name=X509v3 Key Usage, short_name=keyUsage, oid=2.5.29.15, critical=T, value=Certificate Sign, CRL Sign] [name=X509v3 Basic Constraints, short_name=basicConstraints, oid=2.5.29.19, critical=T, value=CA:TRUE, pathlen:0] [name=X509v3 Certificate Policies, short_name=certificatePolicies, oid=2.5.29.32, critical=F, value=Policy: X509v3 Any Policy^J] -[name=X509v3 CRL Distribution Points, short_name=crlDistributionPoints, oid=2.5.29.31, critical=F, value=^JFull Name:^J URI:http://crl.usertrust.com/AddTrustExternalCARoot.crl^J] [name=Authority Information Access, short_name=authorityInfoAccess, oid=1.3.6.1.5.5.7.1.1, critical=F, value=CA Issuers - URI:http://crt.usertrust.com/AddTrustExternalCARoot.p7c^JCA Issuers - URI:http://crt.usertrust.com/AddTrustUTNSGCCA.crt^JOCSP - URI:http://ocsp.usertrust.com^J] [name=X509v3 Subject Key Identifier, short_name=subjectKeyIdentifier, oid=2.5.29.14, critical=F, value=AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A] [name=X509v3 Key Usage, short_name=keyUsage, oid=2.5.29.15, critical=F, value=Certificate Sign, CRL Sign] diff --git a/testing/btest/scripts/base/protocols/ssl/x509_extensions.test b/testing/btest/scripts/base/protocols/ssl/x509_extensions.test index 4db3233b27..c5e0b1b407 100644 --- a/testing/btest/scripts/base/protocols/ssl/x509_extensions.test +++ b/testing/btest/scripts/base/protocols/ssl/x509_extensions.test @@ -3,5 +3,8 @@ event x509_extension(c: connection, is_orig: bool, cert:X509, extension: X509_extension_info) { - print extension; + # The formatting of CRL Distribution Points varies between OpenSSL versions. Skip it + # for the test. + if ( extension$short_name != "crlDistributionPoints" ) + print extension; } From d81bfed45da04d0e77496ea4487832d5aa1f95ba Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 6 Feb 2014 17:52:41 -0800 Subject: [PATCH 061/254] Fixing memory leaks in input framework. --- CHANGES | 7 +++ VERSION | 2 +- aux/btest | 2 +- src/input/Manager.cc | 18 ++++-- .../btest/core/leaks/input-with-remove.bro | 63 +++++++++++++++++++ 5 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 testing/btest/core/leaks/input-with-remove.bro diff --git a/CHANGES b/CHANGES index ce57bfc99e..345e945207 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,11 @@ +2.2-140 | 2014-02-06 17:58:04 -0800 + + * Fixing memory leaks in input framework. (Robin Sommer) + + * Add script to detect filtered TCP traces. Addresses BIT-1119. (Jon + Siwek) + 2.2-137 | 2014-02-04 09:09:55 -0800 * Minor unified2 script documentation fix. (Jon Siwek) diff --git a/VERSION b/VERSION index c869973493..8611c50ec0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2-137 +2.2-140 diff --git a/aux/btest b/aux/btest index 23ff11bf0e..808fd764b6 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit 23ff11bf0edbad2c6f1acbeb3f9a029ff4b61785 +Subproject commit 808fd764b6f5198264177822db3f902f747c21cc diff --git a/src/input/Manager.cc b/src/input/Manager.cc index 7af80892c6..95983faf26 100644 --- a/src/input/Manager.cc +++ b/src/input/Manager.cc @@ -397,7 +397,9 @@ bool Manager::CreateEventStream(RecordVal* fval) string stream_name = name_val->AsString()->CheckString(); Unref(name_val); - RecordType *fields = fval->Lookup("fields", true)->AsType()->AsTypeType()->Type()->AsRecordType(); + Val* fields_val = fval->Lookup("fields", true); + RecordType *fields = fields_val->AsType()->AsTypeType()->Type()->AsRecordType(); + Unref(fields_val); Val *want_record = fval->Lookup("want_record", true); @@ -548,13 +550,17 @@ bool Manager::CreateTableStream(RecordVal* fval) Val* pred = fval->Lookup("pred", true); - RecordType *idx = fval->Lookup("idx", true)->AsType()->AsTypeType()->Type()->AsRecordType(); + Val* idx_val = fval->Lookup("idx", true); + RecordType *idx = idx_val->AsType()->AsTypeType()->Type()->AsRecordType(); + Unref(idx_val); + RecordType *val = 0; - if ( fval->Lookup("val", true) != 0 ) + Val* val_val = fval->Lookup("val", true); + if ( val_val ) { - val = fval->Lookup("val", true)->AsType()->AsTypeType()->Type()->AsRecordType(); - Unref(val); // The lookupwithdefault in the if-clause ref'ed val. + val = val_val->AsType()->AsTypeType()->Type()->AsRecordType(); + Unref(val_val); } TableVal *dst = fval->Lookup("destination", true)->AsTableVal(); @@ -729,7 +735,7 @@ bool Manager::CreateTableStream(RecordVal* fval) stream->pred = pred ? pred->AsFunc() : 0; stream->num_idx_fields = idxfields; stream->num_val_fields = valfields; - stream->tab = dst->AsTableVal(); + stream->tab = dst->AsTableVal(); // ref'd by lookupwithdefault stream->rtype = val ? val->AsRecordType() : 0; stream->itype = idx->AsRecordType(); stream->event = event ? event_registry->Lookup(event->Name()) : 0; diff --git a/testing/btest/core/leaks/input-with-remove.bro b/testing/btest/core/leaks/input-with-remove.bro new file mode 100644 index 0000000000..62fcfa0a4e --- /dev/null +++ b/testing/btest/core/leaks/input-with-remove.bro @@ -0,0 +1,63 @@ +# Needs perftools support. +# +# @TEST-GROUP: leaks +# +# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks +# +# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -b -m -r $TRACES/wikipedia.trace %INPUT +# @TEST-EXEC: btest-bg-wait 15 + +@load base/frameworks/input + +redef exit_only_after_terminate = T; + +global c: count = 0; + + +type OneLine: record { + s: string; +}; + +event line(description: Input::EventDescription, tpe: Input::Event, s: string) + { + print "1", "Line"; + } + +event InputRaw::process_finished(name: string, source:string, exit_code:count, signal_exit:bool) + { + Input::remove(name); + print "2", name; + } + +function run(): count + { + Input::add_event([$name=unique_id(""), + $source=fmt("%s |", "date"), + $reader=Input::READER_RAW, + $mode=Input::STREAM, + $fields=OneLine, + $ev=line, + $want_record=F]); + + return 1; + } + + +event do() + { + run(); + } + +event do_term() { + terminate(); +} + +event bro_init() { + schedule 1sec { + do() + }; + schedule 3sec { + do_term() + }; +} + From b64137761ee73ed10498645124575bf17f5630c9 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 6 Feb 2014 18:20:46 -0800 Subject: [PATCH 062/254] Updating submodule(s). [nomail] --- aux/btest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/btest b/aux/btest index 808fd764b6..14d1f23fff 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit 808fd764b6f5198264177822db3f902f747c21cc +Subproject commit 14d1f23fffff5bcc19d305992dac78cbff83b7be From a048082e688ef9ed3b3d0649dec2a79c1519847a Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 6 Feb 2014 20:23:34 -0800 Subject: [PATCH 063/254] Fixing bug in POP3 analyzer. With certain input the analyzer could end up trying to write to non-writable memory. --- CHANGES | 5 +++++ VERSION | 2 +- src/analyzer/protocol/pop3/POP3.cc | 7 +++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 345e945207..801b7fcd10 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,9 @@ +2.2-142 | 2014-02-06 20:23:34 -0800 + + * Fixing bug in POP3 analyzer. With certain input the analyzer could + end up trying to write to non-writable memory. (Robin Sommer) + 2.2-140 | 2014-02-06 17:58:04 -0800 * Fixing memory leaks in input framework. (Robin Sommer) diff --git a/VERSION b/VERSION index 8611c50ec0..56b1a615cd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2-140 +2.2-142 diff --git a/src/analyzer/protocol/pop3/POP3.cc b/src/analyzer/protocol/pop3/POP3.cc index 388a055ee2..1b6b4c53b6 100644 --- a/src/analyzer/protocol/pop3/POP3.cc +++ b/src/analyzer/protocol/pop3/POP3.cc @@ -192,14 +192,13 @@ void POP3_Analyzer::ProcessRequest(int length, const char* line) case AUTH_CRAM_MD5: { // Format: "userpassword-hash" - char* s; - char* str = (char*) decoded->CheckString(); + const char* s; + const char* str = (char*) decoded->CheckString(); for ( s = str; *s && *s != '\t' && *s != ' '; ++s ) ; - *s = '\0'; - user = str; + user = std::string(str, s); password = ""; break; From c1f626d4ced9312ce132919daa1c92346252e687 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 6 Feb 2014 20:31:02 -0800 Subject: [PATCH 064/254] Updating submodule(s). [nomail] --- aux/broctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/broctl b/aux/broctl index 437333e799..a3f9cc59af 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit 437333e79964b5582f40ae213f69fa96ad590778 +Subproject commit a3f9cc59af51bf51a5a2d6e89b059059345a1d0f From 71df27f9d54b848d606a3bd5ba3755ecf2beb97e Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 6 Feb 2014 20:31:18 -0800 Subject: [PATCH 065/254] Updating submodule(s). [nomail] --- CHANGES | 2 +- VERSION | 2 +- aux/broctl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 801b7fcd10..16d1bb69f4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -2.2-142 | 2014-02-06 20:23:34 -0800 +2.2-144 | 2014-02-06 20:31:18 -0800 * Fixing bug in POP3 analyzer. With certain input the analyzer could end up trying to write to non-writable memory. (Robin Sommer) diff --git a/VERSION b/VERSION index 56b1a615cd..d92d849fbb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2-142 +2.2-144 diff --git a/aux/broctl b/aux/broctl index a3f9cc59af..66793ec3c6 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit a3f9cc59af51bf51a5a2d6e89b059059345a1d0f +Subproject commit 66793ec3c602439e235bee705b654aefb7ac8dec From 2bbf29681ea7151745fc06546e767bde95507bab Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 6 Feb 2014 21:07:46 -0800 Subject: [PATCH 066/254] Updating submodule(s). [nomail] --- aux/btest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/btest b/aux/btest index 14d1f23fff..9d23ca5b7c 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit 14d1f23fffff5bcc19d305992dac78cbff83b7be +Subproject commit 9d23ca5b7ced7fd5ec208d1a074bc40babde9a30 From f11373505deac2bd69ace4f71440c15e94671e13 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Fri, 7 Feb 2014 10:44:31 -0800 Subject: [PATCH 067/254] Updating submodule(s). [nomail] --- aux/btest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/btest b/aux/btest index 9d23ca5b7c..73a736bddb 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit 9d23ca5b7ced7fd5ec208d1a074bc40babde9a30 +Subproject commit 73a736bddb8931afc54bc52b567f639515b19f26 From 741ae7a368f4e58cde2d1db26695db92811224e3 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Fri, 7 Feb 2014 12:51:48 -0800 Subject: [PATCH 068/254] Updating submodule(s). [nomail] --- aux/btest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/btest b/aux/btest index 73a736bddb..9a7b36a44a 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit 73a736bddb8931afc54bc52b567f639515b19f26 +Subproject commit 9a7b36a44a7abeaa1dc2754d3072ab08995c6af8 From adfe3a0754d936de1dbe702848b5bf36fe8c19ed Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Mon, 10 Feb 2014 23:56:23 -0800 Subject: [PATCH 069/254] add channel_id tls extension number. This number is not IANA defined, but we see it being actively used. --- scripts/base/protocols/ssl/consts.bro | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/base/protocols/ssl/consts.bro b/scripts/base/protocols/ssl/consts.bro index 55289a7419..b81aebfbbb 100644 --- a/scripts/base/protocols/ssl/consts.bro +++ b/scripts/base/protocols/ssl/consts.bro @@ -86,6 +86,7 @@ export { [13172] = "next_protocol_negotiation", [13175] = "origin_bound_certificates", [13180] = "encrypted_client_certificates", + [30031] = "channel_id", [65281] = "renegotiation_info" } &default=function(i: count):string { return fmt("unknown-%d", i); }; From 506b26e5ff137f61e087292c0b62453086f5fca9 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Tue, 11 Feb 2014 15:30:22 -0500 Subject: [PATCH 070/254] Expanding the HTTP methods used in the signature to detect HTTP traffic. --- scripts/base/protocols/http/dpd.sig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/base/protocols/http/dpd.sig b/scripts/base/protocols/http/dpd.sig index 13470f4e95..3e264f0bb3 100644 --- a/scripts/base/protocols/http/dpd.sig +++ b/scripts/base/protocols/http/dpd.sig @@ -1,6 +1,8 @@ +# List of HTTP headers pulled from: +# http://annevankesteren.nl/2007/10/http-methods signature dpd_http_client { ip-proto == tcp - payload /^[[:space:]]*(GET|HEAD|POST)[[:space:]]*/ + payload /^[[:space:]]*(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT|PROPFIND|PROPPATCH|MKCOL|COPY|MOVE|LOCK|UNLOCK|VERSION-CONTROL|REPORT|CHECKOUT|CHECKIN|UNCHECKOUT|MKWORKSPACE|UPDATE|LABEL|MERGE|BASELINE-CONTROL|MKACTIVITY|ORDERPATCH|ACL|PATCH|SEARCH|BCOPY|BDELETE|BMOVE|BPROPFIND|BPROPPATCH|NOTIFY|POLL|SUBSCRIBE|UNSUBSCRIBE|X-MS-ENUMATTS|RPC_OUT_DATA|RPC_IN_DATA)[[:space:]]*/ tcp-state originator } @@ -11,3 +13,5 @@ signature dpd_http_server { requires-reverse-signature dpd_http_client enable "http" } + + From 64d73d5a2b76e84b472ee361535f91f2b00a4802 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Tue, 11 Feb 2014 15:41:16 -0800 Subject: [PATCH 071/254] Updating submodule(s). [nomail] --- aux/btest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/btest b/aux/btest index 9a7b36a44a..acdf251b08 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit 9a7b36a44a7abeaa1dc2754d3072ab08995c6af8 +Subproject commit acdf251b08980447b20c72ce0a5e6035665cbc22 From 39be3828fdb7632477cd8d4ccb0e060ca237e16f Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Tue, 11 Feb 2014 16:16:09 -0800 Subject: [PATCH 072/254] Baseline updates for DNS change. I assume these are expected, and in any case it's DS that's being tested not DNS. :) --- .../conn.ds.txt | 4 ++-- .../conn.ds.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/testing/btest/Baseline/scripts.base.frameworks.logging.dataseries.time-as-int/conn.ds.txt b/testing/btest/Baseline/scripts.base.frameworks.logging.dataseries.time-as-int/conn.ds.txt index 5a48439a9f..3bf8a78707 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.logging.dataseries.time-as-int/conn.ds.txt +++ b/testing/btest/Baseline/scripts.base.frameworks.logging.dataseries.time-as-int/conn.ds.txt @@ -54,8 +54,8 @@ # Extent, type='conn' ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents 1300475167096535 CXWv6p3arKYeMETxOg 141.142.220.202 5353 224.0.0.251 5353 udp dns 0 0 0 S0 F 0 D 1 73 0 0 -1300475167097012 CjhGID4nQcgTWjvg4c fe80::217:f2ff:fed7:cf65 5353 ff02::fb 5353 udp 0 0 0 S0 F 0 D 1 199 0 0 -1300475167099816 CCvvfg3TEfuqmmG4bh 141.142.220.50 5353 224.0.0.251 5353 udp 0 0 0 S0 F 0 D 1 179 0 0 +1300475167097012 CjhGID4nQcgTWjvg4c fe80::217:f2ff:fed7:cf65 5353 ff02::fb 5353 udp dns 0 0 0 S0 F 0 D 1 199 0 0 +1300475167099816 CCvvfg3TEfuqmmG4bh 141.142.220.50 5353 224.0.0.251 5353 udp dns 0 0 0 S0 F 0 D 1 179 0 0 1300475168853899 CPbrpk1qSsw6ESzHV4 141.142.220.118 43927 141.142.2.2 53 udp dns 435 38 89 SF F 0 Dd 1 66 1 117 1300475168854378 C6pKV8GSxOnSLghOa 141.142.220.118 37676 141.142.2.2 53 udp dns 420 52 99 SF F 0 Dd 1 80 1 127 1300475168854837 CIPOse170MGiRM1Qf4 141.142.220.118 40526 141.142.2.2 53 udp dns 391 38 183 SF F 0 Dd 1 66 1 211 diff --git a/testing/btest/Baseline/scripts.base.frameworks.logging.dataseries.wikipedia/conn.ds.txt b/testing/btest/Baseline/scripts.base.frameworks.logging.dataseries.wikipedia/conn.ds.txt index 8f486c30e0..a82439c1e0 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.logging.dataseries.wikipedia/conn.ds.txt +++ b/testing/btest/Baseline/scripts.base.frameworks.logging.dataseries.wikipedia/conn.ds.txt @@ -54,8 +54,8 @@ # Extent, type='conn' ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents 1300475167.096535 CXWv6p3arKYeMETxOg 141.142.220.202 5353 224.0.0.251 5353 udp dns 0.000000 0 0 S0 F 0 D 1 73 0 0 -1300475167.097012 CjhGID4nQcgTWjvg4c fe80::217:f2ff:fed7:cf65 5353 ff02::fb 5353 udp 0.000000 0 0 S0 F 0 D 1 199 0 0 -1300475167.099816 CCvvfg3TEfuqmmG4bh 141.142.220.50 5353 224.0.0.251 5353 udp 0.000000 0 0 S0 F 0 D 1 179 0 0 +1300475167.097012 CjhGID4nQcgTWjvg4c fe80::217:f2ff:fed7:cf65 5353 ff02::fb 5353 udp dns 0.000000 0 0 S0 F 0 D 1 199 0 0 +1300475167.099816 CCvvfg3TEfuqmmG4bh 141.142.220.50 5353 224.0.0.251 5353 udp dns 0.000000 0 0 S0 F 0 D 1 179 0 0 1300475168.853899 CPbrpk1qSsw6ESzHV4 141.142.220.118 43927 141.142.2.2 53 udp dns 0.000435 38 89 SF F 0 Dd 1 66 1 117 1300475168.854378 C6pKV8GSxOnSLghOa 141.142.220.118 37676 141.142.2.2 53 udp dns 0.000420 52 99 SF F 0 Dd 1 80 1 127 1300475168.854837 CIPOse170MGiRM1Qf4 141.142.220.118 40526 141.142.2.2 53 udp dns 0.000392 38 183 SF F 0 Dd 1 66 1 211 From f45bd84f4ca65b235d17963dc97b4c152fd8ad57 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Tue, 11 Feb 2014 16:16:49 -0800 Subject: [PATCH 073/254] Updating submodule(s). [nomail] --- aux/btest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/btest b/aux/btest index acdf251b08..c3a65f1306 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit acdf251b08980447b20c72ce0a5e6035665cbc22 +Subproject commit c3a65f13063291ffcfd6d05c09d7724c02e9a40d From 6563b544d8b5e532006682acc3313c5989ce0fe5 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 12 Feb 2014 17:00:12 -0600 Subject: [PATCH 074/254] Fix memory leak in modbus analyzer. Would happen if there's a 'modbus_read_fifo_queue_response' event handler. --- .../protocol/modbus/modbus-analyzer.pac | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/analyzer/protocol/modbus/modbus-analyzer.pac b/src/analyzer/protocol/modbus/modbus-analyzer.pac index a9c773b9e9..c2d009c961 100644 --- a/src/analyzer/protocol/modbus/modbus-analyzer.pac +++ b/src/analyzer/protocol/modbus/modbus-analyzer.pac @@ -10,6 +10,7 @@ %header{ VectorVal* bytestring_to_coils(bytestring coils, uint quantity); RecordVal* HeaderToBro(ModbusTCP_TransportHeader *header); + VectorVal* create_vector_of_count(); %} %code{ @@ -30,6 +31,14 @@ return modbus_header; } + VectorVal* create_vector_of_count() + { + VectorType* vt = new VectorType(base_type(TYPE_COUNT)); + VectorVal* vv = new VectorVal(vt); + Unref(vt); + return vv; + } + %} refine flow ModbusTCP_Flow += { @@ -367,7 +376,7 @@ refine flow ModbusTCP_Flow += { if ( ::modbus_read_file_record_request ) { //TODO: this need to be a vector of some Reference Request record type - //VectorVal *t = new VectorVal(new VectorType(base_type(TYPE_COUNT))); + //VectorVal *t = create_vector_of_count(); //for ( unsigned int i = 0; i < (${message.references}->size()); ++i ) // { // Val* r = new Val((${message.references[i].ref_type}), TYPE_COUNT); @@ -393,7 +402,7 @@ refine flow ModbusTCP_Flow += { %{ if ( ::modbus_read_file_record_response ) { - //VectorVal *t = new VectorVal(new VectorType(base_type(TYPE_COUNT))); + //VectorVal *t = create_vector_of_count(); //for ( unsigned int i = 0; i < ${message.references}->size(); ++i ) // { // //TODO: work the reference type in here somewhere @@ -414,7 +423,7 @@ refine flow ModbusTCP_Flow += { %{ if ( ::modbus_write_file_record_request ) { - //VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_COUNT))); + //VectorVal* t = create_vector_of_count(); //for ( unsigned int i = 0; i < (${message.references}->size()); ++i ) // { // Val* r = new Val((${message.references[i].ref_type}), TYPE_COUNT); @@ -447,7 +456,7 @@ refine flow ModbusTCP_Flow += { %{ if ( ::modbus_write_file_record_response ) { - //VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_COUNT))); + //VectorVal* t = create_vector_of_count(); //for ( unsigned int i = 0; i < (${messages.references}->size()); ++i ) // { // Val* r = new Val((${message.references[i].ref_type}), TYPE_COUNT); @@ -589,7 +598,7 @@ refine flow ModbusTCP_Flow += { if ( ::modbus_read_fifo_queue_response ) { - VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_COUNT))); + VectorVal* t = create_vector_of_count(); for ( unsigned int i = 0; i < (${message.register_data})->size(); ++i ) { Val* r = new Val(${message.register_data[i]}, TYPE_COUNT); From e844727e7339a95054e05cdf8634d6fd47044e74 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 12 Feb 2014 17:03:51 -0600 Subject: [PATCH 075/254] Increase timeouts of some unit tests. --- testing/btest/core/leaks/basic-cluster.bro | 2 +- testing/btest/core/leaks/dataseries.bro | 2 +- testing/btest/core/leaks/file-analysis-http-get.bro | 2 +- testing/btest/core/leaks/hll_cluster.bro | 2 +- testing/btest/core/leaks/input-reread.bro | 2 +- testing/btest/core/leaks/test-all.bro | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/testing/btest/core/leaks/basic-cluster.bro b/testing/btest/core/leaks/basic-cluster.bro index 2c13c2315c..2d93469850 100644 --- a/testing/btest/core/leaks/basic-cluster.bro +++ b/testing/btest/core/leaks/basic-cluster.bro @@ -9,7 +9,7 @@ # @TEST-EXEC: sleep 1 # @TEST-EXEC: btest-bg-run worker-1 HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local BROPATH=$BROPATH:.. CLUSTER_NODE=worker-1 bro -m %INPUT # @TEST-EXEC: btest-bg-run worker-2 HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local BROPATH=$BROPATH:.. CLUSTER_NODE=worker-2 bro -m %INPUT -# @TEST-EXEC: btest-bg-wait 15 +# @TEST-EXEC: btest-bg-wait 25 @TEST-START-FILE cluster-layout.bro redef Cluster::nodes = { diff --git a/testing/btest/core/leaks/dataseries.bro b/testing/btest/core/leaks/dataseries.bro index 61c9c030e9..fcb5782f4e 100644 --- a/testing/btest/core/leaks/dataseries.bro +++ b/testing/btest/core/leaks/dataseries.bro @@ -8,4 +8,4 @@ # # @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks # @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -r $TRACES/wikipedia.trace Log::default_writer=Log::WRITER_DATASERIES -# @TEST-EXEC: btest-bg-wait 15 +# @TEST-EXEC: btest-bg-wait 25 diff --git a/testing/btest/core/leaks/file-analysis-http-get.bro b/testing/btest/core/leaks/file-analysis-http-get.bro index 8256f3e6da..aa4708305e 100644 --- a/testing/btest/core/leaks/file-analysis-http-get.bro +++ b/testing/btest/core/leaks/file-analysis-http-get.bro @@ -5,7 +5,7 @@ # @TEST-GROUP: leaks # # @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -r $TRACES/http/get.trace $SCRIPTS/file-analysis-test.bro %INPUT -# @TEST-EXEC: btest-bg-wait 15 +# @TEST-EXEC: btest-bg-wait 25 redef test_file_analysis_source = "HTTP"; diff --git a/testing/btest/core/leaks/hll_cluster.bro b/testing/btest/core/leaks/hll_cluster.bro index a6f704a677..a843452e00 100644 --- a/testing/btest/core/leaks/hll_cluster.bro +++ b/testing/btest/core/leaks/hll_cluster.bro @@ -10,7 +10,7 @@ # @TEST-EXEC: sleep 2 # @TEST-EXEC: btest-bg-run worker-1 HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local BROPATH=$BROPATH:.. CLUSTER_NODE=worker-1 bro runnumber=1 %INPUT # @TEST-EXEC: btest-bg-run worker-2 HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local BROPATH=$BROPATH:.. CLUSTER_NODE=worker-2 bro runnumber=2 %INPUT -# @TEST-EXEC: btest-bg-wait 10 +# @TEST-EXEC: btest-bg-wait 25 # # @TEST-EXEC: btest-diff manager-1/.stdout # @TEST-EXEC: btest-diff worker-1/.stdout diff --git a/testing/btest/core/leaks/input-reread.bro b/testing/btest/core/leaks/input-reread.bro index fa37f04ede..c6ff5361be 100644 --- a/testing/btest/core/leaks/input-reread.bro +++ b/testing/btest/core/leaks/input-reread.bro @@ -14,7 +14,7 @@ # @TEST-EXEC: cp input4.log input.log # @TEST-EXEC: sleep 5 # @TEST-EXEC: cp input5.log input.log -# @TEST-EXEC: btest-bg-wait 15 +# @TEST-EXEC: btest-bg-wait 30 @TEST-START-FILE input1.log #separator \x09 diff --git a/testing/btest/core/leaks/test-all.bro b/testing/btest/core/leaks/test-all.bro index acba16bd6d..7cdccb202a 100644 --- a/testing/btest/core/leaks/test-all.bro +++ b/testing/btest/core/leaks/test-all.bro @@ -5,4 +5,4 @@ # @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks # # @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -r $TRACES/wikipedia.trace test-all-policy -# @TEST-EXEC: btest-bg-wait 15 +# @TEST-EXEC: btest-bg-wait 25 From dd0856a57f386b12819b7ef54b141d2d706539d8 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Wed, 12 Feb 2014 22:38:59 -0500 Subject: [PATCH 076/254] HTTP CONNECT proxy support. - The HTTP analyzer now supports handling HTTP CONNECT proxies same as the SOCKS analyzer handles proxying. --- scripts/base/protocols/http/main.bro | 11 ++++++ src/analyzer/protocol/http/HTTP.cc | 35 ++++++++++++++++++ src/analyzer/protocol/http/HTTP.h | 4 ++ src/types.bif | 1 + .../conn.log | 10 +++++ .../http.log | 10 +++++ .../smtp.log | 10 +++++ .../tunnel.log | 10 +++++ .../btest/Traces/http/connect-with-smtp.trace | Bin 0 -> 4191 bytes .../base/protocols/http/http-connect.bro | 11 ++++++ 10 files changed, 102 insertions(+) create mode 100644 testing/btest/Baseline/scripts.base.protocols.http.http-connect/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.http.http-connect/http.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.http.http-connect/smtp.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.http.http-connect/tunnel.log create mode 100644 testing/btest/Traces/http/connect-with-smtp.trace create mode 100644 testing/btest/scripts/base/protocols/http/http-connect.bro diff --git a/scripts/base/protocols/http/main.bro b/scripts/base/protocols/http/main.bro index a164fcd6a6..27257be2d6 100644 --- a/scripts/base/protocols/http/main.bro +++ b/scripts/base/protocols/http/main.bro @@ -4,6 +4,7 @@ @load base/utils/numbers @load base/utils/files +@load base/frameworks/tunnels module HTTP; @@ -217,6 +218,16 @@ event http_reply(c: connection, version: string, code: count, reason: string) &p c$http$info_code = code; c$http$info_msg = reason; } + + if ( c$http?$method && c$http$method == "CONNECT" && code == 200 ) + { + # Copy this conn_id and set the orig_p to zero because in the case of CONNECT proxies there will + # be potentially many source ports since a new proxy connection is established for each + # proxied connection. We treat this as a singular "tunnel". + local tid = copy(c$id); + tid$orig_p = 0/tcp; + Tunnel::register([$cid=tid, $tunnel_type=Tunnel::HTTP]); + } } event http_header(c: connection, is_orig: bool, name: string, value: string) &priority=5 diff --git a/src/analyzer/protocol/http/HTTP.cc b/src/analyzer/protocol/http/HTTP.cc index f605dce402..93dbfbcb2e 100644 --- a/src/analyzer/protocol/http/HTTP.cc +++ b/src/analyzer/protocol/http/HTTP.cc @@ -889,6 +889,9 @@ HTTP_Analyzer::HTTP_Analyzer(Connection* conn) reply_code = 0; reply_reason_phrase = 0; + connect_request = false; + pia = 0; + content_line_orig = new tcp::ContentLine_Analyzer(conn, true); AddSupportAnalyzer(content_line_orig); @@ -945,6 +948,14 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) if ( TCP() && TCP()->IsPartial() ) return; + if ( pia ) + { + // There will be a PIA instance if this connection has been identified + // as a connect proxy. + ForwardStream(len, data, is_orig); + return; + } + const char* line = reinterpret_cast(data); const char* end_of_line = line + len; @@ -1059,6 +1070,27 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) reply_message, is_orig, ExpectReplyMessageBody(), len); + + if ( connect_request && reply_code == 200 ) + { + pia = new pia::PIA_TCP(Conn()); + if ( AddChildAnalyzer(pia) ) + { + pia->FirstPacket(true, 0); + pia->FirstPacket(false, 0); + + // This connection has transitioned to no longer + // being http and the content line support analyzers + // need to be removed. + RemoveSupportAnalyzer(content_line_orig); + RemoveSupportAnalyzer(content_line_resp); + } + else + { + pia = 0; + } + } + } else { @@ -1404,6 +1436,9 @@ void HTTP_Analyzer::HTTP_Request() // DEBUG_MSG("%.6f http_request\n", network_time); ConnectionEvent(http_request, vl); } + + if ( strcasecmp_n(request_method->AsString()->Len(), (const char*) (request_method->AsString()->Bytes()), "CONNECT") == 0 ) + connect_request = true; } void HTTP_Analyzer::HTTP_Reply() diff --git a/src/analyzer/protocol/http/HTTP.h b/src/analyzer/protocol/http/HTTP.h index a1fedee41d..48a611b63b 100644 --- a/src/analyzer/protocol/http/HTTP.h +++ b/src/analyzer/protocol/http/HTTP.h @@ -5,6 +5,7 @@ #include "analyzer/protocol/tcp/TCP.h" #include "analyzer/protocol/tcp/ContentLine.h" +#include "analyzer/protocol/pia/PIA.h" #include "analyzer/protocol/zip/ZIP.h" #include "analyzer/protocol/mime/MIME.h" #include "binpac_bro.h" @@ -237,6 +238,9 @@ protected: int connection_close; int request_ongoing, reply_ongoing; + bool connect_request; + pia::PIA_TCP *pia; + Val* request_method; // request_URI is in the original form (may contain '%' diff --git a/src/types.bif b/src/types.bif index 2931bf2d22..a44c3c1615 100644 --- a/src/types.bif +++ b/src/types.bif @@ -186,6 +186,7 @@ enum Type %{ TEREDO, SOCKS, GTPv1, + HTTP, %} type EncapsulatingConn: record; diff --git a/testing/btest/Baseline/scripts.base.protocols.http.http-connect/conn.log b/testing/btest/Baseline/scripts.base.protocols.http.http-connect/conn.log new file mode 100644 index 0000000000..8b639edd93 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.http.http-connect/conn.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open 2014-02-13-03-37-02 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string bool count string count count count count table[string] +1078232251.833846 CXWv6p3arKYeMETxOg 79.26.245.236 3378 254.228.86.79 8240 tcp http,smtp 6.722274 1685 223 SF - 0 ShADadfF 14 2257 16 944 (empty) +#close 2014-02-13-03-37-02 diff --git a/testing/btest/Baseline/scripts.base.protocols.http.http-connect/http.log b/testing/btest/Baseline/scripts.base.protocols.http.http-connect/http.log new file mode 100644 index 0000000000..4a2cf1ad17 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.http.http-connect/http.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path http +#open 2014-02-13-03-37-02 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth method host uri referrer user_agent request_body_len response_body_len status_code status_msg info_code info_msg filename tags username password proxied orig_fuids orig_mime_types resp_fuids resp_mime_types +#types time string addr port addr port count string string string string string count count count string count string string table[enum] string string table[string] vector[string] vector[string] vector[string] vector[string] +1078232252.284420 CXWv6p3arKYeMETxOg 79.26.245.236 3378 254.228.86.79 8240 1 CONNECT - mailin03.sul.t-online.de:25 / - - 0 0 200 Connection established - - - (empty) - - - - - - - +#close 2014-02-13-03-37-02 diff --git a/testing/btest/Baseline/scripts.base.protocols.http.http-connect/smtp.log b/testing/btest/Baseline/scripts.base.protocols.http.http-connect/smtp.log new file mode 100644 index 0000000000..e11a7e9ac0 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.http.http-connect/smtp.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path smtp +#open 2014-02-13-03-37-02 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth helo mailfrom rcptto date from to reply_to msg_id in_reply_to subject x_originating_ip first_received second_received last_reply path user_agent fuids +#types time string addr port addr port count string string table[string] string string table[string] string string string string addr string string string vector[addr] string vector[string] +1078232255.642953 CXWv6p3arKYeMETxOg 79.26.245.236 3378 254.228.86.79 8240 1 208.191.73.21 Tue, 2 Mar 2004 13:57:49 +0100 Sybille Ostermann thenightwatch@t-online.de - - - Hier sind die dicken Girls hemmungloser denn je.. grcu - from mail.iosphere.net (mail.iosphere.net [216.58.97.33]) by mail.netsync.net with esmtp; Mrz, 02 2004 12:55:34 -0700 - 250 Message accepted. 254.228.86.79,79.26.245.236,216.58.97.33 Microsoft Outlook Build 10.0.2616 FVS9k93PUgScEUCOjd +#close 2014-02-13-03-37-02 diff --git a/testing/btest/Baseline/scripts.base.protocols.http.http-connect/tunnel.log b/testing/btest/Baseline/scripts.base.protocols.http.http-connect/tunnel.log new file mode 100644 index 0000000000..9e18e38e03 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.http.http-connect/tunnel.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path tunnel +#open 2014-02-13-03-37-02 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p tunnel_type action +#types time string addr port addr port enum enum +1078232252.284420 - 79.26.245.236 0 254.228.86.79 8240 Tunnel::HTTP Tunnel::DISCOVER +#close 2014-02-13-03-37-02 diff --git a/testing/btest/Traces/http/connect-with-smtp.trace b/testing/btest/Traces/http/connect-with-smtp.trace new file mode 100644 index 0000000000000000000000000000000000000000..dba5e69edc0c5c10ecf25db2bb50c46aa6b88ad7 GIT binary patch literal 4191 zcmcgvU2Ggz6~4P(r^%8PDM-{nqMmJETc3 zE|G7u9l~t_d_i$ zBovB-C1Uxl6^K4o4Y!8)&i(;%dc$))5>29l8cTig?1nEO>YGn~E`Is5c^~mY9r0I) zXtamO4xCYrCXVe3Px%}_AK>^VqTZL=GQV{5Iw6PTlSE?uC>0_vmrcYP_J z845^w-?p%}HMb>xD0jb%QEn0|av(yE;JzHS6t752_PURC=F4khwZ#wZ?j@ui5~NfW zhHcJi!DTiF>bUx}$sB_g>%@=zY*T}H&{gdV7k!ogvRY+rD`spbX6(;5XIEzInKw3( zZy;wmnuuHP`NU6u93Z~a7XgWrlDjQ#tYfq0%naQ~09~rNY*$0fkjm_zWui;>}`RVHwtQS2vM8 zD6Sk$YhuSow|uPU16VR!XL4=xFGdcdHAWxJqAhxrWM5L*-le3HHNn1eY;(g0O$Ppl zFPIlJ@EOdViUuCdz99+8O|pFZ@y%ox?#t2SgXBMbEVnPB z5$^aBAx9BOj;5emP!@&Hd}~1VQ^@=kWInt16d@yn`N3H9H<-d>-64`g7364g#L#V@ zTBSYUh*yvr`W8MMdySB;bT>Mp1F(V#7iO4iKv8#fw1~uS3Ad8H*eK-)svLS`@q3bM z<-GvcGsyKKay|O&zffiBdV(i%x@%~#zgAj`8kB@>0WUGm+&QKGk7j}P`a%6)o;;jV zdz7S#3k%oRk%wS<4hn{_xipwAij39{P z9|dU0Hl{G!sTx#JAE>?g)ZtXJM@jc8ecP3;t{MgZCY;xq1< zjN&L%D2Fj7Oa}~VSspK&wu846v4X&Hswhwv1rGrzFH-Tp^U5%bCZ?!xusLhszk^`6 zb}4rg`MD}Z(sb7CteQIG{pciJIMjXQ0p{3=-rjUyBKbfpI-0~&s<~={?in9;dcVBQ%HazrPaL>7_M8@ zIy+}(W)xpwms0NF%a~$0Fik7AWjQX4cnDcATvo=($~ZBFLC4gfM!0Sb7VVF402*xGV_c*Q{YRQZW`#RpAp%yBSKPvB_0)=s@ zD`$^I2TjzFvso010_IU$*EohQtE#A&63C&mb70w~DIMwSrN~X9j$wGra#^+NyBjlH z!S$wB(5W)*lW1>rV^!SYWva;sR=5?HU$I~difu=JJfL6Y4OYpJ%SqQ~D;6u6Me7M( zC{<(8<;E0$bwv|xs-AcJ>RDQ&dJc@>Yt`j(Y)p;nx#@>7lEFhcnwsdYk9{oqaG;4| zB}S~a_~mnzT7S<_$I($3y-=W4mll!e6)er8>2RaWH+TE%vNW5ouP)64BUqZRVh0@? zeu0p$er+PZjCEzb518A7T z9PuYR8dUf{{$%&YFOC1SrY|8 Date: Thu, 13 Feb 2014 12:45:51 -0800 Subject: [PATCH 077/254] Revert "Expanding the HTTP methods used in the signature to detect HTTP traffic." This reverts commit 506b26e5ff137f61e087292c0b62453086f5fca9. The corresponding patch adding HTTP CONNECT support doesn't work yet so backing this out until we get that in shape. --- scripts/base/protocols/http/dpd.sig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/scripts/base/protocols/http/dpd.sig b/scripts/base/protocols/http/dpd.sig index 3e264f0bb3..13470f4e95 100644 --- a/scripts/base/protocols/http/dpd.sig +++ b/scripts/base/protocols/http/dpd.sig @@ -1,8 +1,6 @@ -# List of HTTP headers pulled from: -# http://annevankesteren.nl/2007/10/http-methods signature dpd_http_client { ip-proto == tcp - payload /^[[:space:]]*(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT|PROPFIND|PROPPATCH|MKCOL|COPY|MOVE|LOCK|UNLOCK|VERSION-CONTROL|REPORT|CHECKOUT|CHECKIN|UNCHECKOUT|MKWORKSPACE|UPDATE|LABEL|MERGE|BASELINE-CONTROL|MKACTIVITY|ORDERPATCH|ACL|PATCH|SEARCH|BCOPY|BDELETE|BMOVE|BPROPFIND|BPROPPATCH|NOTIFY|POLL|SUBSCRIBE|UNSUBSCRIBE|X-MS-ENUMATTS|RPC_OUT_DATA|RPC_IN_DATA)[[:space:]]*/ + payload /^[[:space:]]*(GET|HEAD|POST)[[:space:]]*/ tcp-state originator } @@ -13,5 +11,3 @@ signature dpd_http_server { requires-reverse-signature dpd_http_client enable "http" } - - From 3c95d1d695ed80d7796b680fd31fa8f3afaf8ad3 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 13 Feb 2014 14:55:45 -0600 Subject: [PATCH 078/254] Refactor DNS script's state management to improve performance. The amount of timers involved in DNS::PendingMessage tables' expiration attributes have a significant performance hit. Instead the script now relies solely on maximum thresholds for pending message quantities to limit amount of accumulated state. There's a new option, "DNS::max_pending_query_ids", to limit the number outstanding messages across all DNS query IDs ("DNS::max_pending_msgs" still limits number of outstanding messages for a *given* query ID). --- scripts/base/protocols/dns/main.bro | 64 +++++++++---------- .../weird.log | 5 +- 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/scripts/base/protocols/dns/main.bro b/scripts/base/protocols/dns/main.bro index 21a0711159..294220d1f2 100644 --- a/scripts/base/protocols/dns/main.bro +++ b/scripts/base/protocols/dns/main.bro @@ -109,16 +109,6 @@ export { ## DNS message query/transaction ID. type PendingMessages: table[count] of Queue::Queue; - ## Called when a pending DNS query has not been matched with a reply (or - ## vice versa) in a sufficent amount of time. - ## - ## pending: table of pending messages, indexed by transaction ID. - ## - ## id: the index of he element being expired. - ## - ## Returns: amount of time to delay expiration of the element. - global expire_pending_msg: function(pending: PendingMessages, id: count): interval; - ## The amount of time that DNS queries or replies for a given ## query/transaction ID are allowed to be queued while waiting for ## a matching reply or query. @@ -131,16 +121,21 @@ export { ## response is ongoing). const max_pending_msgs = 50 &redef; + ## Give up trying to match pending DNS queries or replies across all + ## query/transaction IDs once there is at least one unmatched query or + ## reply across this number of different query IDs. + const max_pending_query_ids = 50 &redef; + ## A record type which tracks the status of DNS queries for a given ## :bro:type:`connection`. type State: record { ## Indexed by query id, returns Info record corresponding to ## queries that haven't been matched with a response yet. - pending_queries: PendingMessages &read_expire=pending_msg_expiry_interval &expire_func=expire_pending_msg; + pending_queries: PendingMessages; ## Indexed by query id, returns Info record corresponding to ## replies that haven't been matched with a query yet. - pending_replies: PendingMessages &read_expire=pending_msg_expiry_interval &expire_func=expire_pending_msg; + pending_replies: PendingMessages; }; } @@ -176,7 +171,11 @@ function log_unmatched_msgs_queue(q: Queue::Queue) Queue::get_vector(q, infos); for ( i in infos ) + { + event flow_weird("dns_unmatched_msg", + infos[i]$id$orig_h, infos[i]$id$resp_h); Log::write(DNS::LOG, infos[i]); + } } function log_unmatched_msgs(msgs: PendingMessages) @@ -191,16 +190,28 @@ function log_unmatched_msgs(msgs: PendingMessages) function enqueue_new_msg(msgs: PendingMessages, id: count, msg: Info) { if ( id !in msgs ) - msgs[id] = Queue::init(); - else if ( Queue::len(msgs[id]) > max_pending_msgs ) { - local info: Info = Queue::peek(msgs[id]); - event flow_weird("dns_unmatched_msg_quantity", info$id$orig_h, - info$id$resp_h); - log_unmatched_msgs_queue(msgs[id]); - # Throw away all unmatched on assumption they'll never be matched. + if ( |msgs| > max_pending_query_ids ) + { + event flow_weird("dns_unmatched_query_id_quantity", + msg$id$orig_h, msg$id$resp_h); + # Throw away all unmatched on assumption they'll never be matched. + log_unmatched_msgs(msgs); + } + msgs[id] = Queue::init(); } + else + { + if ( Queue::len(msgs[id]) > max_pending_msgs ) + { + event flow_weird("dns_unmatched_msg_quantity", + msg$id$orig_h, msg$id$resp_h); + log_unmatched_msgs_queue(msgs[id]); + # Throw away all unmatched on assumption they'll never be matched. + msgs[id] = Queue::init(); + } + } Queue::put(msgs[id], msg); } @@ -447,18 +458,3 @@ event connection_state_remove(c: connection) &priority=-5 log_unmatched_msgs(c$dns_state$pending_queries); log_unmatched_msgs(c$dns_state$pending_replies); } - -function expire_pending_msg(pending: PendingMessages, id: count): interval - { - local infos: vector of Info; - Queue::get_vector(pending[id], infos); - - for ( i in infos ) - { - Log::write(DNS::LOG, infos[i]); - event flow_weird("dns_unmatched_msg", infos[i]$id$orig_h, - infos[i]$id$resp_h); - } - - return 0sec; - } diff --git a/testing/btest/Baseline/scripts.base.protocols.dns.duplicate-reponses/weird.log b/testing/btest/Baseline/scripts.base.protocols.dns.duplicate-reponses/weird.log index 175a474425..295de4ec2c 100644 --- a/testing/btest/Baseline/scripts.base.protocols.dns.duplicate-reponses/weird.log +++ b/testing/btest/Baseline/scripts.base.protocols.dns.duplicate-reponses/weird.log @@ -3,9 +3,10 @@ #empty_field (empty) #unset_field - #path weird -#open 2013-08-26-19-36-33 +#open 2014-02-13-20-36-35 #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer #types time string addr port addr port string string bool string 1363716396.798286 CXWv6p3arKYeMETxOg 55.247.223.174 27285 222.195.43.124 53 DNS_RR_unknown_type - F bro 1363716396.798374 CXWv6p3arKYeMETxOg 55.247.223.174 27285 222.195.43.124 53 dns_unmatched_reply - F bro -#close 2013-08-26-19-36-33 +1363716396.798374 - - - - - dns_unmatched_msg - F bro +#close 2014-02-13-20-36-35 From ba81aa438766d34e59752ae6c3dccf52a9f1353c Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Fri, 14 Feb 2014 12:06:24 -0800 Subject: [PATCH 079/254] Support for MPLS over VLAN. Patch by Chris Kanich. BIT-1017 #merged --- CHANGES | 4 ++++ VERSION | 2 +- src/PktSrc.cc | 22 ++++++++++++------ .../btest/Baseline/core.mpls-in-vlan/conn.log | 12 ++++++++++ testing/btest/Traces/mpls-in-vlan.trace | Bin 0 -> 2605 bytes testing/btest/core/mpls-in-vlan.bro | 2 ++ 6 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 testing/btest/Baseline/core.mpls-in-vlan/conn.log create mode 100644 testing/btest/Traces/mpls-in-vlan.trace create mode 100644 testing/btest/core/mpls-in-vlan.bro diff --git a/CHANGES b/CHANGES index f00e43a271..ba9102aeeb 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,8 @@ +2.2-174 | 2014-02-14 12:07:04 -0800 + + * Support for MPLS over VLAN. (Chris Kanich) + 2.2-173 | 2014-02-14 10:50:15 -0800 * Fix misidentification of SOCKS traffic that in particiular seemed diff --git a/VERSION b/VERSION index 60dee2b058..5b847786b5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2-173 +2.2-174 diff --git a/src/PktSrc.cc b/src/PktSrc.cc index 941c4acd83..179630cdbd 100644 --- a/src/PktSrc.cc +++ b/src/PktSrc.cc @@ -229,12 +229,21 @@ void PktSrc::Process() { // MPLS carried over the ethernet frame. case 0x8847: + // Remove the data link layer and denote a + // header size of zero before the IP header. have_mpls = true; + data += get_link_header_size(datalink); + pkt_hdr_size = 0; break; // VLAN carried over the ethernet frame. case 0x8100: data += get_link_header_size(datalink); + + // Check for MPLS in VLAN. + if ( ((data[2] << 8) + data[3]) == 0x8847 ) + have_mpls = true; + data += 4; // Skip the vlan header pkt_hdr_size = 0; @@ -274,8 +283,13 @@ void PktSrc::Process() protocol = (data[2] << 8) + data[3]; if ( protocol == 0x0281 ) - // MPLS Unicast + { + // MPLS Unicast. Remove the data link layer and + // denote a header size of zero before the IP header. have_mpls = true; + data += get_link_header_size(datalink); + pkt_hdr_size = 0; + } else if ( protocol != 0x0021 && protocol != 0x0057 ) { @@ -290,12 +304,6 @@ void PktSrc::Process() if ( have_mpls ) { - // Remove the data link layer - data += get_link_header_size(datalink); - - // Denote a header size of zero before the IP header - pkt_hdr_size = 0; - // Skip the MPLS label stack. bool end_of_stack = false; diff --git a/testing/btest/Baseline/core.mpls-in-vlan/conn.log b/testing/btest/Baseline/core.mpls-in-vlan/conn.log new file mode 100644 index 0000000000..e8ee793b75 --- /dev/null +++ b/testing/btest/Baseline/core.mpls-in-vlan/conn.log @@ -0,0 +1,12 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open 2014-02-14-20-04-20 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string bool count string count count count count table[string] +1371685686.536606 CXWv6p3arKYeMETxOg 65.65.65.65 19244 65.65.65.65 80 tcp - - - - OTH - 0 D 1 257 0 0 (empty) +1371686961.156859 CjhGID4nQcgTWjvg4c 65.65.65.65 32828 65.65.65.65 80 tcp - - - - OTH - 0 d 0 0 1 1500 (empty) +1371686961.479321 CCvvfg3TEfuqmmG4bh 65.65.65.65 61193 65.65.65.65 80 tcp - - - - OTH - 0 D 1 710 0 0 (empty) +#close 2014-02-14-20-04-20 diff --git a/testing/btest/Traces/mpls-in-vlan.trace b/testing/btest/Traces/mpls-in-vlan.trace new file mode 100644 index 0000000000000000000000000000000000000000..634f3fce1469f61f436ed1b79c5b1c42f8c29289 GIT binary patch literal 2605 zcmc&$O>7%Q6rKc{rYlxd;*t}LWDX_rdhM86Wl5!&#EGR8$t5We327Pcj@LuRGt2Bc zPFf)h5>ig|g2V+ODpi~~fdq$~T7E9v5Jyy1LeN{0IKY)RyIv=@TnSf2j5IrXGjHC! z@0<7L?a$wSd1Dqmj?s+wT8KmDxu-Sz%iRH=NB z(qv!%;^>*P;@M1ZiqSOAG>NwxDA^Uh#X2OQj*x=BIJ)3TE|rs8UtiY?1F2N2ER`?7 z#5<;ui)ARt-X$h>@ikCsaY=v|#e#OMx4^Q4mx|%O7Lr+~bUu|r8L@<2(u^eU#`w8dxVpAhTf;By;Ogd9y}C25lE{lT++v6M5biO=^w6W@DV%E(NCo94 z_vd=4qIOIB2RGhx+RXQ<(9kd`{iA>`*r*O-=!<9^8bu zLPz>tPSb__1Z92PApXkbGMqG}&30K^Xi5ddW!~Wu1Ovn#^Kou9X@g1Q{%@q`U9uTc)% z*Tg!dH20=t3k-4gz%w}0r(^(^G(N1qS!Qz<0U_}Lr&fFr0xekB4*9y8g_f0-C^~V|1_~h2_d+zDNPyGe&@YY9zVtMn;JN2Vi z7apouX2$==@kG5&>u|4Ep!)<~U|NtW7%jxRx)8(b|FDJlQR9T0_BA+P2&~X zqKc}qe~CwZ=znZ4!(`QjC)27KTxDV2r!8F+^O5hhhdP&t2)g?30aIaJ*~&u|c>7|p Ja6$j^`~zPp1hfDE literal 0 HcmV?d00001 diff --git a/testing/btest/core/mpls-in-vlan.bro b/testing/btest/core/mpls-in-vlan.bro new file mode 100644 index 0000000000..f57c1862ce --- /dev/null +++ b/testing/btest/core/mpls-in-vlan.bro @@ -0,0 +1,2 @@ +# @TEST-EXEC: bro -C -r $TRACES/mpls-in-vlan.trace +# @TEST-EXEC: btest-diff conn.log From b712d6436cfbfe48c0afcb0a2fd30bfd07a4687b Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Tue, 18 Feb 2014 02:54:03 -0800 Subject: [PATCH 080/254] update 3rdparty submodule (new SQLite version) --- src/3rdparty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rdparty b/src/3rdparty index 42a4c9694a..92674c5745 160000 --- a/src/3rdparty +++ b/src/3rdparty @@ -1 +1 @@ -Subproject commit 42a4c9694a2b2677b050fbb7cbae26bc5ec4605a +Subproject commit 92674c57455cb71de5a2be6f482570e10be46aa6 From a0c06a957bf3c7fd60748f7b5074bff8cbd86868 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 18 Feb 2014 14:41:32 -0600 Subject: [PATCH 081/254] Add SNMP datagram parsing support. This supports parsing of SNMPv1 (RFC 1157), SNMPv2 (RFC 1901/3416), and SNMPv2 (RFC 3412). An event is raised for each SNMP PDU type, though there's not currently any event handlers for them and not a default snmp.log either. However, simple presence of SNMP is currently visible now in conn.log service field and known_services.log. --- scripts/base/init-bare.bro | 124 ++++ scripts/base/init-default.bro | 1 + scripts/base/protocols/snmp/README | 1 + scripts/base/protocols/snmp/__load__.bro | 1 + scripts/base/protocols/snmp/main.bro | 15 + src/analyzer/protocol/CMakeLists.txt | 1 + src/analyzer/protocol/snmp/CMakeLists.txt | 11 + src/analyzer/protocol/snmp/Plugin.cc | 9 + src/analyzer/protocol/snmp/SNMP.cc | 38 ++ src/analyzer/protocol/snmp/SNMP.h | 29 + src/analyzer/protocol/snmp/events.bif | 166 +++++ src/analyzer/protocol/snmp/snmp-analyzer.pac | 590 +++++++++++++++++ src/analyzer/protocol/snmp/snmp-protocol.pac | 272 ++++++++ src/analyzer/protocol/snmp/snmp.pac | 25 + src/analyzer/protocol/snmp/types.bif | 18 + .../Baseline/core.print-bpf-filters/output2 | 10 +- .../canonified_loaded_scripts.log | 6 +- .../canonified_loaded_scripts.log | 8 +- .../scripts.base.protocols.snmp.v1/out1 | 598 ++++++++++++++++++ .../scripts.base.protocols.snmp.v1/out2 | 26 + .../scripts.base.protocols.snmp.v1/out3 | 18 + .../scripts.base.protocols.snmp.v1/out4 | 11 + .../scripts.base.protocols.snmp.v2/out1 | 18 + .../scripts.base.protocols.snmp.v2/out2 | 18 + .../scripts.base.protocols.snmp.v2/out3 | 72 +++ .../scripts.base.protocols.snmp.v3/out1 | 34 + testing/btest/Traces/snmp/snmpv1_get.pcap | Bin 0 -> 7165 bytes .../btest/Traces/snmp/snmpv1_get_short.pcap | Bin 0 -> 299 bytes testing/btest/Traces/snmp/snmpv1_set.pcap | Bin 0 -> 219 bytes testing/btest/Traces/snmp/snmpv1_trap.pcap | Bin 0 -> 143 bytes testing/btest/Traces/snmp/snmpv2_get.pcap | Bin 0 -> 233 bytes .../btest/Traces/snmp/snmpv2_get_bulk.pcap | Bin 0 -> 214 bytes .../btest/Traces/snmp/snmpv2_get_next.pcap | Bin 0 -> 894 bytes .../btest/Traces/snmp/snmpv3_get_next.pcap | Bin 0 -> 661 bytes .../btest/scripts/base/protocols/snmp/v1.bro | 11 + .../btest/scripts/base/protocols/snmp/v2.bro | 9 + .../btest/scripts/base/protocols/snmp/v3.bro | 5 + testing/scripts/snmp-test.bro | 208 ++++++ 38 files changed, 2345 insertions(+), 8 deletions(-) create mode 100644 scripts/base/protocols/snmp/README create mode 100644 scripts/base/protocols/snmp/__load__.bro create mode 100644 scripts/base/protocols/snmp/main.bro create mode 100644 src/analyzer/protocol/snmp/CMakeLists.txt create mode 100644 src/analyzer/protocol/snmp/Plugin.cc create mode 100644 src/analyzer/protocol/snmp/SNMP.cc create mode 100644 src/analyzer/protocol/snmp/SNMP.h create mode 100644 src/analyzer/protocol/snmp/events.bif create mode 100644 src/analyzer/protocol/snmp/snmp-analyzer.pac create mode 100644 src/analyzer/protocol/snmp/snmp-protocol.pac create mode 100644 src/analyzer/protocol/snmp/snmp.pac create mode 100644 src/analyzer/protocol/snmp/types.bif create mode 100644 testing/btest/Baseline/scripts.base.protocols.snmp.v1/out1 create mode 100644 testing/btest/Baseline/scripts.base.protocols.snmp.v1/out2 create mode 100644 testing/btest/Baseline/scripts.base.protocols.snmp.v1/out3 create mode 100644 testing/btest/Baseline/scripts.base.protocols.snmp.v1/out4 create mode 100644 testing/btest/Baseline/scripts.base.protocols.snmp.v2/out1 create mode 100644 testing/btest/Baseline/scripts.base.protocols.snmp.v2/out2 create mode 100644 testing/btest/Baseline/scripts.base.protocols.snmp.v2/out3 create mode 100644 testing/btest/Baseline/scripts.base.protocols.snmp.v3/out1 create mode 100644 testing/btest/Traces/snmp/snmpv1_get.pcap create mode 100644 testing/btest/Traces/snmp/snmpv1_get_short.pcap create mode 100644 testing/btest/Traces/snmp/snmpv1_set.pcap create mode 100644 testing/btest/Traces/snmp/snmpv1_trap.pcap create mode 100644 testing/btest/Traces/snmp/snmpv2_get.pcap create mode 100644 testing/btest/Traces/snmp/snmpv2_get_bulk.pcap create mode 100644 testing/btest/Traces/snmp/snmpv2_get_next.pcap create mode 100644 testing/btest/Traces/snmp/snmpv3_get_next.pcap create mode 100644 testing/btest/scripts/base/protocols/snmp/v1.bro create mode 100644 testing/btest/scripts/base/protocols/snmp/v2.bro create mode 100644 testing/btest/scripts/base/protocols/snmp/v3.bro create mode 100644 testing/scripts/snmp-test.bro diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index d4e631ecf4..7e3840df0a 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2775,6 +2775,130 @@ export { } module GLOBAL; +@load base/bif/plugins/Bro_SNMP.types.bif + +module SNMP; +export { + + ## The top-level message data structure of an SNMPv1 datagram, not + ## including the PDU data. See :rfc:`1157`. + type SNMP::HeaderV1: record { + community: string; + }; + + ## The top-level message data structure of an SNMPv2 datagram, not + ## including the PDU data. See :rfc:`1901`. + type SNMP::HeaderV2: record { + community: string; + }; + + ## The ``ScopedPduData`` data structure of an SNMPv3 datagram, not + ## including the PDU data (i.e. just the "context" fields). + ## See :rfc:`3412`. + type SNMP::ScopedPDU_Context: record { + engine_id: string; + name: string; + }; + + ## The top-level message data structure of an SNMPv3 datagram, not + ## including the PDU data. See :rfc:`3412`. + type SNMP::HeaderV3: record { + id: count; + max_size: count; + flags: count; + auth_flag: bool; + priv_flag: bool; + reportable_flag: bool; + security_model: count; + security_params: string; + pdu_context: SNMP::ScopedPDU_Context &optional; + }; + + ## A generic SNMP header data structure that may include data from + ## any version of SNMP. The value of the ``version`` field + ## determines what header field is initialized. + type SNMP::Header: record { + version: count; + v1: SNMP::HeaderV1 &optional; ##< Set when ``version`` is 0. + v2: SNMP::HeaderV2 &optional; ##< Set when ``version`` is 1. + v3: SNMP::HeaderV3 &optional; ##< Set when ``version`` is 3. + }; + + ## A generic SNMP object value, that may include any of the + ## valid ``ObjectSyntax`` values from :rfc:`1155` or :rfc:`3416`. + ## The value is decoded whenever possible and assigned to + ## the appropriate field, which can be determined from the value + ## of the ``tag`` field. For tags that can't be mapped to an + ## appropriate type, the ``octets`` field holds the BER encoded + ## ASN.1 content if there is any (though, ``octets`` is may also + ## be used for other tags such as OCTET STRINGS or Opaque). Null + ## values will only have their corresponding tag value set. + type SNMP::ObjectValue: record { + tag: count; + oid: string &optional; + signed: int &optional; + unsigned: count &optional; + address: addr &optional; + octets: string &optional; + }; + + # These aren't an enum because it's easier to type fields as count. + # That way don't have to deal with type conversion, plus doesn't + # mislead that these are the only valid tag values (it's just the set + # of known tags). + const SNMP::OBJ_INTEGER_TAG : count = 0x02; ##< Signed 64-bit integer. + const SNMP::OBJ_OCTETSTRING_TAG : count = 0x04; ##< An octet string. + const SNMP::OBJ_UNSPECIFIED_TAG : count = 0x05; ##< A NULL value. + const SNMP::OBJ_OID_TAG : count = 0x06; ##< An Object Identifier. + const SNMP::OBJ_IPADDRESS_TAG : count = 0x40; ##< An IP address. + const SNMP::OBJ_COUNTER32_TAG : count = 0x41; ##< Unsigned 32-bit integer. + const SNMP::OBJ_UNSIGNED32_TAG : count = 0x42; ##< Unsigned 32-bit integer. + const SNMP::OBJ_TIMETICKS_TAG : count = 0x43; ##< Unsigned 32-bit integer. + const SNMP::OBJ_OPAQUE_TAG : count = 0x44; ##< An octet string. + const SNMP::OBJ_COUNTER64_TAG : count = 0x46; ##< Unsigned 64-bit integer. + const SNMP::OBJ_NOSUCHOBJECT_TAG : count = 0x80; ##< A NULL value. + const SNMP::OBJ_NOSUCHINSTANCE_TAG: count = 0x81; ##< A NULL value. + const SNMP::OBJ_ENDOFMIBVIEW_TAG : count = 0x82; ##< A NULL value. + + ## The ``VarBind`` data structure from either :rfc:`1157` or + ## :rfc:`3416`, which maps an Object Identifier to a value. + type SNMP::Binding: record { + oid: string; + value: SNMP::ObjectValue; + }; + + ## A ``VarBindList`` data structure from either :rfc:`1157` or :rfc:`3416`. + ## A sequences of :bro:see:`SNMP::Binding`, which maps an OIDs to values. + type SNMP::Bindings: vector of SNMP::Binding; + + ## A ``PDU`` data structure from either :rfc:`1157` or :rfc:`3416`. + type SNMP::PDU: record { + request_id: int; + error_status: int; + error_index: int; + bindings: SNMP::Bindings; + }; + + ## A ``Trap-PDU`` data structure from :rfc:`1157`. + type SNMP::TrapPDU: record { + enterprise: string; + agent: addr; + generic_trap: int; + specific_trap: int; + time_stamp: count; + bindings: SNMP::Bindings; + }; + + ## A ``BulkPDU`` data structure from :rfc:`3416`. + type SNMP::BulkPDU: record { + request_id: int; + non_repeaters: count; + max_repititions: count; + bindings: SNMP::Bindings; + }; +} +module GLOBAL; + @load base/bif/event.bif ## BPF filter the user has set via the -f command line options. Empty if none. diff --git a/scripts/base/init-default.bro b/scripts/base/init-default.bro index d87574f4e5..edf6e21f56 100644 --- a/scripts/base/init-default.bro +++ b/scripts/base/init-default.bro @@ -47,6 +47,7 @@ @load base/protocols/irc @load base/protocols/modbus @load base/protocols/pop3 +@load base/protocols/snmp @load base/protocols/smtp @load base/protocols/socks @load base/protocols/ssh diff --git a/scripts/base/protocols/snmp/README b/scripts/base/protocols/snmp/README new file mode 100644 index 0000000000..524c3266cc --- /dev/null +++ b/scripts/base/protocols/snmp/README @@ -0,0 +1 @@ +Support for Simple Network Management Protocol (SNMP) analysis. diff --git a/scripts/base/protocols/snmp/__load__.bro b/scripts/base/protocols/snmp/__load__.bro new file mode 100644 index 0000000000..a10fe855df --- /dev/null +++ b/scripts/base/protocols/snmp/__load__.bro @@ -0,0 +1 @@ +@load ./main diff --git a/scripts/base/protocols/snmp/main.bro b/scripts/base/protocols/snmp/main.bro new file mode 100644 index 0000000000..a2fbb23713 --- /dev/null +++ b/scripts/base/protocols/snmp/main.bro @@ -0,0 +1,15 @@ +##! Enables analysis of SNMP datagrams. + +module SNMP; + +export { +} + +const ports = { 161/udp, 162/udp }; + +redef likely_server_ports += { ports }; + +event bro_init() &priority=5 + { + Analyzer::register_for_ports(Analyzer::ANALYZER_SNMP, ports); + } diff --git a/src/analyzer/protocol/CMakeLists.txt b/src/analyzer/protocol/CMakeLists.txt index fc63aa4b66..bf063dfafc 100644 --- a/src/analyzer/protocol/CMakeLists.txt +++ b/src/analyzer/protocol/CMakeLists.txt @@ -28,6 +28,7 @@ add_subdirectory(ntp) add_subdirectory(pia) add_subdirectory(pop3) add_subdirectory(rpc) +add_subdirectory(snmp) add_subdirectory(smb) add_subdirectory(smtp) add_subdirectory(socks) diff --git a/src/analyzer/protocol/snmp/CMakeLists.txt b/src/analyzer/protocol/snmp/CMakeLists.txt new file mode 100644 index 0000000000..7f1ffe2ed6 --- /dev/null +++ b/src/analyzer/protocol/snmp/CMakeLists.txt @@ -0,0 +1,11 @@ +include(BroPlugin) + +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}) + +bro_plugin_begin(Bro SNMP) +bro_plugin_cc(SNMP.cc Plugin.cc) +bro_plugin_bif(types.bif) +bro_plugin_bif(events.bif) +bro_plugin_pac(snmp.pac snmp-protocol.pac snmp-analyzer.pac) +bro_plugin_end() diff --git a/src/analyzer/protocol/snmp/Plugin.cc b/src/analyzer/protocol/snmp/Plugin.cc new file mode 100644 index 0000000000..e9e74f67a6 --- /dev/null +++ b/src/analyzer/protocol/snmp/Plugin.cc @@ -0,0 +1,9 @@ +#include "plugin/Plugin.h" +#include "SNMP.h" + +BRO_PLUGIN_BEGIN(Bro, SNMP) + BRO_PLUGIN_DESCRIPTION("SNMP Analyzer"); + BRO_PLUGIN_ANALYZER("SNMP", snmp::SNMP_Analyzer); + BRO_PLUGIN_BIF_FILE(types); + BRO_PLUGIN_BIF_FILE(events); +BRO_PLUGIN_END diff --git a/src/analyzer/protocol/snmp/SNMP.cc b/src/analyzer/protocol/snmp/SNMP.cc new file mode 100644 index 0000000000..110479406c --- /dev/null +++ b/src/analyzer/protocol/snmp/SNMP.cc @@ -0,0 +1,38 @@ +#include "SNMP.h" +#include "Func.h" +#include "types.bif.h" +#include "events.bif.h" + +using namespace analyzer::snmp; + +SNMP_Analyzer::SNMP_Analyzer(Connection* conn) + : Analyzer("SNMP", conn) + { + interp = new binpac::SNMP::SNMP_Conn(this); + } + +SNMP_Analyzer::~SNMP_Analyzer() + { + delete interp; + } + +void SNMP_Analyzer::Done() + { + Analyzer::Done(); + Event(udp_session_done); + } + +void SNMP_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, + int seq, const IP_Hdr* ip, int caplen) + { + Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen); + + try + { + interp->NewData(orig, data, data + len); + } + catch ( const binpac::Exception& e ) + { + ProtocolViolation(e.c_msg()); + } + } diff --git a/src/analyzer/protocol/snmp/SNMP.h b/src/analyzer/protocol/snmp/SNMP.h new file mode 100644 index 0000000000..f6dedc7b87 --- /dev/null +++ b/src/analyzer/protocol/snmp/SNMP.h @@ -0,0 +1,29 @@ +#ifndef ANALYZER_PROTOCOL_SNMP_SNMP_H +#define ANALYZER_PROTOCOL_SNMP_SNMP_H + +#include "snmp_pac.h" + +namespace analyzer { namespace snmp { + +class SNMP_Analyzer : public analyzer::Analyzer { + +public: + + SNMP_Analyzer(Connection* conn); + virtual ~SNMP_Analyzer(); + + virtual void Done(); + virtual void DeliverPacket(int len, const u_char* data, bool orig, + int seq, const IP_Hdr* ip, int caplen); + + static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn) + { return new SNMP_Analyzer(conn); } + +protected: + + binpac::SNMP::SNMP_Conn* interp; +}; + +} } // namespace analyzer::* + +#endif diff --git a/src/analyzer/protocol/snmp/events.bif b/src/analyzer/protocol/snmp/events.bif new file mode 100644 index 0000000000..af5f2ba969 --- /dev/null +++ b/src/analyzer/protocol/snmp/events.bif @@ -0,0 +1,166 @@ + +## An SNMP ``GetRequest-PDU`` message from either :rfc:`1157` or :rfc:`3416`. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +## +## pdu: An SNMP PDU data structure. +event snmp_get_request%(c: connection, is_orig: bool, header: SNMP::Header, + pdu: SNMP::PDU%); + +## An SNMP ``GetNextRequest-PDU`` message from either :rfc:`1157` or +## :rfc:`3416`. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +## +## pdu: An SNMP PDU data structure. +event snmp_get_next_request%(c: connection, is_orig: bool, + header: SNMP::Header, pdu: SNMP::PDU%); + +## An SNMP ``GetResponse-PDU`` message from :rfc:`1157` or a +## ``Response-PDU`` from :rfc:`3416`. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +## +## pdu: An SNMP PDU data structure. +event snmp_response%(c: connection, is_orig: bool, header: SNMP::Header, + pdu: SNMP::PDU%); + +## An SNMP ``SetRequest-PDU`` message from either :rfc:`1157` or :rfc:`3416`. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +## +## pdu: An SNMP PDU data structure. +event snmp_set_request%(c: connection, is_orig: bool, header: SNMP::Header, + pdu: SNMP::PDU%); + +## An SNMP ``Trap-PDU`` message from :rfc:`1157`. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +## +## pdu: An SNMP PDU data structure. +event snmp_trap%(c: connection, is_orig: bool, header: SNMP::Header, + pdu: SNMP::TrapPDU%); + +## An SNMP ``GetBulkRequest-PDU`` message from :rfc:`3416`. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +## +## pdu: An SNMP PDU data structure. +event snmp_get_bulk_request%(c: connection, is_orig: bool, + header: SNMP::Header, pdu: SNMP::BulkPDU%); + +## An SNMP ``InformRequest-PDU`` message from :rfc:`3416`. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +## +## pdu: An SNMP PDU data structure. +event snmp_inform_request%(c: connection, is_orig: bool, header: SNMP::Header, + pdu: SNMP::PDU%); + +## An SNMP ``SNMPv2-Trap-PDU`` message from :rfc:`1157`. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +## +## pdu: An SNMP PDU data structure. +event snmp_trapV2%(c: connection, is_orig: bool, header: SNMP::Header, + pdu: SNMP::PDU%); + +## An SNMP ``Report-PDU`` message from :rfc:`3416`. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +## +## pdu: An SNMP PDU data structure. +event snmp_report%(c: connection, is_orig: bool, header: SNMP::Header, + pdu: SNMP::PDU%); + +## An SNMP PDU message of unknown type. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +## +## tag: The tag of the unknown SNMP PDU. +event snmp_unknown_pdu%(c: connection, is_orig: bool, header: SNMP::Header, + tag: count%); + +## An SNMPv3 ``ScopedPDUData`` of unknown type (neither plaintext or +## an encrypted PDU was in the datagram). +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +## +## tag: The tag of the unknown SNMP PDU scope. +event snmp_unknown_scoped_pdu%(c: connection, is_orig: bool, + header: SNMP::Header, tag: count%); + +## An SNMPv3 encrypted PDU message. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## header: SNMP version-dependent data that precedes PDU data in the top-level +## SNMP message structure. +event snmp_encrypted_pdu%(c: connection, is_orig: bool, header: SNMP::Header%); + +## A datagram with an unknown SNMP version. +## +## c: The connection overwhich the SNMP datagram is sent. +## +## is_orig: The endpoint which sent the SNMP datagram. +## +## version: The value of the unknown SNMP version. +event snmp_unknown_header_version%(c: connection, is_orig: bool, + version: count%); diff --git a/src/analyzer/protocol/snmp/snmp-analyzer.pac b/src/analyzer/protocol/snmp/snmp-analyzer.pac new file mode 100644 index 0000000000..1a864df8b9 --- /dev/null +++ b/src/analyzer/protocol/snmp/snmp-analyzer.pac @@ -0,0 +1,590 @@ + +%header{ +StringVal* asn1_oid_to_val(const ASN1Encoding* oid); +StringVal* asn1_oid_to_val(const ASN1ObjectIdentifier* oid); + +Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t); +Val* asn1_integer_to_val(const ASN1Integer* i, TypeTag t); + +StringVal* asn1_octet_string_to_val(const ASN1Encoding* s); +StringVal* asn1_octet_string_to_val(const ASN1OctetString* s); + +AddrVal* network_address_to_val(const ASN1Encoding* na); +AddrVal* network_address_to_val(const NetworkAddress* na); + +Val* asn1_obj_to_val(const ASN1Encoding* obj); + +RecordVal* build_hdr(const Header* header); +RecordVal* build_hdrV3(const Header* header); +VectorVal* build_bindings(const VarBindList* vbl); +RecordVal* build_pdu(const CommonPDU* pdu); +RecordVal* build_trap_pdu(const TrapPDU* pdu); +RecordVal* build_bulk_pdu(const GetBulkRequestPDU* pdu); +%} + +%code{ + +StringVal* asn1_oid_to_val(const ASN1ObjectIdentifier* oid) + { + return asn1_oid_to_val(oid->encoding()); + } + +StringVal* asn1_oid_to_val(const ASN1Encoding* oid) + { + vector oid_components; + vector > subidentifiers; + vector subidentifier_values; + vector subidentifier; + bytestring const& bs = oid->content(); + + for ( int i = 0; i < bs.length(); ++i ) + { + if ( bs[i] & 0x80 ) + subidentifier.push_back(bs[i] & 0x7f); + else + { + subidentifier.push_back(bs[i]); + subidentifiers.push_back(subidentifier); + subidentifier.clear(); + } + } + + if ( ! subidentifier.empty() || subidentifiers.size() < 1 ) + // Underflow. + return new StringVal(""); + + for ( size_t i = 0; i < subidentifiers.size(); ++i ) + { + subidentifier = subidentifiers[i]; + uint64 value = 0; + + for ( size_t j = 0; j < subidentifier.size(); ++j ) + { + uint64 byte = subidentifier[j]; + value |= byte << (7 * (subidentifier.size() - (j + 1))); + } + + subidentifier_values.push_back(value); + } + + string rval; + + for ( size_t i = 0; i < subidentifier_values.size(); ++i ) + { + char tmp[32]; + + if ( i > 0 ) + { + rval += "."; + snprintf(tmp, sizeof(tmp), "%"PRIu64, subidentifier_values[i]); + rval += tmp; + } + else + { + std::div_t result = div(subidentifier_values[i], 40); + snprintf(tmp, sizeof(tmp), "%d", result.quot); + rval += tmp; + rval += "."; + snprintf(tmp, sizeof(tmp), "%d", result.rem); + rval += tmp; + } + } + + return new StringVal(rval); + } + +Val* asn1_obj_to_val(const ASN1Encoding* obj) + { + RecordVal* rval = new RecordVal(BifType::Record::SNMP::ObjectValue); + uint8 tag = obj->meta()->tag(); + + rval->Assign(0, new Val(tag, TYPE_COUNT)); + + switch ( tag ) { + case VARBIND_UNSPECIFIED_TAG: + case VARBIND_NOSUCHOBJECT_TAG: + case VARBIND_NOSUCHINSTANCE_TAG: + case VARBIND_ENDOFMIBVIEW_TAG: + break; + + case ASN1_OBJECT_IDENTIFIER_TAG: + rval->Assign(1, asn1_oid_to_val(obj)); + break; + + case ASN1_INTEGER_TAG: + rval->Assign(2, asn1_integer_to_val(obj, TYPE_INT)); + break; + + case APP_COUNTER32_TAG: + case APP_UNSIGNED32_TAG: + case APP_TIMETICKS_TAG: + case APP_COUNTER64_TAG: + rval->Assign(3, asn1_integer_to_val(obj, TYPE_COUNT)); + break; + + case APP_IPADDRESS_TAG: + rval->Assign(4, network_address_to_val(obj)); + break; + + case ASN1_OCTET_STRING_TAG: + case APP_OPAQUE_TAG: + default: + rval->Assign(5, asn1_octet_string_to_val(obj)); + break; + } + + return rval; + } + +StringVal* asn1_octet_string_to_val(const ASN1OctetString* s) + { + return asn1_octet_string_to_val(s->encoding()); + } + +StringVal* asn1_octet_string_to_val(const ASN1Encoding* s) + { + bytestring const& bs = s->content(); + return new StringVal(bs.length(), reinterpret_cast(bs.data())); + } + +Val* asn1_integer_to_val(const ASN1Integer* i, TypeTag t) + { + return asn1_integer_to_val(i->encoding(), t); + } + +Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t) + { + return new Val(binary_to_int64(i->content()), t); + } + +AddrVal* network_address_to_val(const NetworkAddress* na) + { + return network_address_to_val(na->encoding()); + } + +AddrVal* network_address_to_val(const ASN1Encoding* na) + { + bytestring const& bs = na->content(); + + // IPv6 can probably be presumed to be a octet string of length 16, + // but standards don't seem to currently make any provisions for IPv6, + // so ignore anything that can't be IPv4. + if ( bs.length() != 4 ) + return new AddrVal(IPAddr()); + + const u_char* data = reinterpret_cast(bs.data()); + uint32 network_order = extract_uint32(data); + return new AddrVal(network_order); + } + +Val* time_ticks_to_val(const TimeTicks* tt) + { + return asn1_integer_to_val(tt->asn1_integer(), TYPE_COUNT); + } + +RecordVal* build_hdr(const Header* header) + { + RecordVal* rv = new RecordVal(BifType::Record::SNMP::Header); + rv->Assign(0, new Val(header->version(), TYPE_COUNT)); + + switch ( header->version() ) { + case SNMPV1_TAG: + { + RecordVal* v1 = new RecordVal(BifType::Record::SNMP::HeaderV1); + v1->Assign(0, asn1_octet_string_to_val(header->v1()->community())); + rv->Assign(1, v1); + } + break; + + case SNMPV2_TAG: + { + RecordVal* v2 = new RecordVal(BifType::Record::SNMP::HeaderV2); + v2->Assign(0, asn1_octet_string_to_val(header->v2()->community())); + rv->Assign(2, v2); + } + break; + + case SNMPV3_TAG: + { + rv->Assign(3, build_hdrV3(header)); + } + break; + } + + return rv; + } + +RecordVal* build_hdrV3(const Header* header) + { + RecordVal* v3 = new RecordVal(BifType::Record::SNMP::HeaderV3); + const v3Header* v3hdr = header->v3(); + const v3HeaderData* global_data = v3hdr->global_data(); + bytestring const& flags = global_data->flags()->encoding()->content(); + uint8 flags_byte = flags.length() > 0 ? flags[0] : 0; + + v3->Assign(0, asn1_integer_to_val(global_data->id(), TYPE_COUNT)); + v3->Assign(1, asn1_integer_to_val(global_data->max_size(), + TYPE_COUNT)); + v3->Assign(2, new Val(flags_byte, TYPE_COUNT)); + v3->Assign(3, new Val(flags_byte & 0x01, TYPE_BOOL)); + v3->Assign(4, new Val(flags_byte & 0x02, TYPE_BOOL)); + v3->Assign(5, new Val(flags_byte & 0x04, TYPE_BOOL)); + v3->Assign(6, asn1_integer_to_val(global_data->security_model(), + TYPE_COUNT)); + v3->Assign(7, asn1_octet_string_to_val(v3hdr->security_parameters())); + + if ( v3hdr->next()->tag() == ASN1_SEQUENCE_TAG ) + { + const v3ScopedPDU* spdu = v3hdr->plaintext_pdu(); + RecordVal* rv = new RecordVal(BifType::Record::SNMP::ScopedPDU_Context); + rv->Assign(0, asn1_octet_string_to_val(spdu->context_engine_id())); + rv->Assign(1, asn1_octet_string_to_val(spdu->context_name())); + v3->Assign(8, rv); + } + + return v3; + } + +VectorVal* build_bindings(const VarBindList* vbl) + { + VectorVal* vv = new VectorVal(BifType::Vector::SNMP::Bindings); + + for ( size_t i = 0; i < vbl->bindings()->size(); ++i ) + { + VarBind* vb = (*vbl->bindings())[i]; + RecordVal* binding = new RecordVal(BifType::Record::SNMP::Binding); + binding->Assign(0, asn1_oid_to_val(vb->name()->oid())); + binding->Assign(1, asn1_obj_to_val(vb->value()->encoding())); + vv->Assign(i, binding); + } + + return vv; + } + +RecordVal* build_pdu(const CommonPDU* pdu) + { + RecordVal* rv = new RecordVal(BifType::Record::SNMP::PDU); + rv->Assign(0, asn1_integer_to_val(pdu->request_id(), TYPE_INT)); + rv->Assign(1, asn1_integer_to_val(pdu->error_status(), TYPE_INT)); + rv->Assign(2, asn1_integer_to_val(pdu->error_index(), TYPE_INT)); + rv->Assign(3, build_bindings(pdu->var_bindings())); + return rv; + } + +RecordVal* build_trap_pdu(const TrapPDU* pdu) + { + RecordVal* rv = new RecordVal(BifType::Record::SNMP::TrapPDU); + rv->Assign(0, asn1_oid_to_val(pdu->enterprise())); + rv->Assign(1, network_address_to_val(pdu->agent_addr())); + rv->Assign(2, asn1_integer_to_val(pdu->generic_trap(), TYPE_INT)); + rv->Assign(3, asn1_integer_to_val(pdu->specific_trap(), TYPE_INT)); + rv->Assign(4, time_ticks_to_val(pdu->time_stamp())); + rv->Assign(5, build_bindings(pdu->var_bindings())); + return rv; + } + +RecordVal* build_bulk_pdu(const GetBulkRequestPDU* pdu) + { + RecordVal* rv = new RecordVal(BifType::Record::SNMP::BulkPDU); + rv->Assign(0, asn1_integer_to_val(pdu->request_id(), TYPE_INT)); + rv->Assign(1, asn1_integer_to_val(pdu->non_repeaters(), TYPE_COUNT)); + rv->Assign(2, asn1_integer_to_val(pdu->max_repititions(), TYPE_COUNT)); + rv->Assign(3, build_bindings(pdu->var_bindings())); + return rv; + } +%} + +refine connection SNMP_Conn += { + + function proc_get_request(pdu: GetRequestPDU): bool + %{ + if ( ! snmp_get_request ) + return false; + + BifEvent::generate_snmp_get_request(bro_analyzer(), + bro_analyzer()->Conn(), + ${pdu.header.is_orig}, + build_hdr(${pdu.header}), + build_pdu(${pdu.pdu})); + return true; + %} + + function proc_get_next_request(pdu: GetNextRequestPDU): bool + %{ + if ( ! snmp_get_next_request ) + return false; + + BifEvent::generate_snmp_get_next_request(bro_analyzer(), + bro_analyzer()->Conn(), + ${pdu.header.is_orig}, + build_hdr(${pdu.header}), + build_pdu(${pdu.pdu})); + return true; + %} + + function proc_response(pdu: ResponsePDU): bool + %{ + if ( ! snmp_response ) + return false; + + BifEvent::generate_snmp_response(bro_analyzer(), + bro_analyzer()->Conn(), + ${pdu.header.is_orig}, + build_hdr(${pdu.header}), + build_pdu(${pdu.pdu})); + return true; + %} + + function proc_set_request(pdu: SetRequestPDU): bool + %{ + if ( ! snmp_set_request ) + return false; + + BifEvent::generate_snmp_set_request(bro_analyzer(), + bro_analyzer()->Conn(), + ${pdu.header.is_orig}, + build_hdr(${pdu.header}), + build_pdu(${pdu.pdu})); + return true; + %} + + function proc_trap(pdu: TrapPDU): bool + %{ + if ( ! snmp_trap ) + return false; + + BifEvent::generate_snmp_trap(bro_analyzer(), + bro_analyzer()->Conn(), + ${pdu.header.is_orig}, + build_hdr(${pdu.header}), + build_trap_pdu(${pdu})); + return true; + %} + + function proc_get_bulk_request(pdu: GetBulkRequestPDU): bool + %{ + if ( ! snmp_get_bulk_request ) + return false; + + BifEvent::generate_snmp_get_bulk_request(bro_analyzer(), + bro_analyzer()->Conn(), + ${pdu.header.is_orig}, + build_hdr(${pdu.header}), + build_bulk_pdu(${pdu})); + return true; + %} + + function proc_inform_request(pdu: InformRequestPDU): bool + %{ + if ( ! snmp_inform_request ) + return false; + + BifEvent::generate_snmp_inform_request(bro_analyzer(), + bro_analyzer()->Conn(), + ${pdu.header.is_orig}, + build_hdr(${pdu.header}), + build_pdu(${pdu.pdu})); + return true; + %} + + function proc_v2_trap(pdu: v2TrapPDU): bool + %{ + if ( ! snmp_trapV2 ) + return false; + + BifEvent::generate_snmp_trapV2(bro_analyzer(), + bro_analyzer()->Conn(), + ${pdu.header.is_orig}, + build_hdr(${pdu.header}), + build_pdu(${pdu.pdu})); + return true; + %} + + function proc_report(pdu: ReportPDU): bool + %{ + if ( ! snmp_report ) + return false; + + BifEvent::generate_snmp_report(bro_analyzer(), + bro_analyzer()->Conn(), + ${pdu.header.is_orig}, + build_hdr(${pdu.header}), + build_pdu(${pdu.pdu})); + return true; + %} + + function proc_unknown_version_header(rec: UnknownVersionHeader): bool + %{ + if ( ! snmp_unknown_header_version ) + return false; + + BifEvent::generate_snmp_unknown_header_version(bro_analyzer(), + bro_analyzer()->Conn(), + ${rec.header.is_orig}, + ${rec.header.version}); + return true; + %} + + function proc_unknown_pdu(rec: UnknownPDU): bool + %{ + if ( ! snmp_unknown_pdu ) + return false; + + BifEvent::generate_snmp_unknown_pdu(bro_analyzer(), + bro_analyzer()->Conn(), + ${rec.header.is_orig}, + build_hdr(${rec.header}), + ${rec.tag}); + return true; + %} + + function proc_unknown_scoped_pdu(rec: UnknownScopedPDU): bool + %{ + if ( ! snmp_unknown_scoped_pdu ) + return false; + + BifEvent::generate_snmp_unknown_scoped_pdu(bro_analyzer(), + bro_analyzer()->Conn(), + ${rec.header.is_orig}, + build_hdr(${rec.header}), + ${rec.tag}); + return true; + %} + + function proc_encrypted_pdu(rec: EncryptedPDU): bool + %{ + if ( ! snmp_encrypted_pdu ) + return false; + + BifEvent::generate_snmp_encrypted_pdu(bro_analyzer(), + bro_analyzer()->Conn(), + ${rec.header.is_orig}, + build_hdr(${rec.header})); + return true; + %} + + function proc_header(rec: Header): bool + %{ + if ( rec->unknown() ) + return false; + + bro_analyzer()->ProtocolConfirmation(); + return true; + %} + + function proc_v3_header_data(rec: v3HeaderData): bool + %{ + if ( rec->flags()->encoding()->content().length() == 1 ) + return true; + + bro_analyzer()->ProtocolViolation("Invalid v3 HeaderData msgFlags"); + return false; + %} + + function check_tag(rec: ASN1EncodingMeta, expect: uint8): bool + %{ + if ( rec->tag() == expect ) + return true; + + // Unwind now to stop parsing because it's definitely the + // wrong protocol and parsing further could be expensive. + // Upper layer of analyzer will catch and call ProtocolViolation(). + throw binpac::Exception(fmt("Got ASN.1 tag %d, expect %d", + rec->tag(), expect)); + return false; + %} + + function check_int_width(rec: ASN1Integer): bool + %{ + int len = rec->encoding()->content().length(); + + if ( len <= 9 ) + // All integers use two's complement form, so an unsigned 64-bit + // integer value can require 9 octets to encode if the highest + // order bit is set. + return true; + + throw binpac::Exception(fmt("ASN.1 integer width overflow: %d", len)); + return false; + %} + + function check_int(rec: ASN1Integer): bool + %{ + return check_tag(rec->encoding()->meta(), ASN1_INTEGER_TAG) && + check_int_width(rec); + %} +}; + +refine typeattr GetRequestPDU += &let { + proc: bool = $context.connection.proc_get_request(this); +}; +refine typeattr GetNextRequestPDU += &let { + proc: bool = $context.connection.proc_get_next_request(this); +}; +refine typeattr ResponsePDU += &let { + proc: bool = $context.connection.proc_response(this); +}; +refine typeattr SetRequestPDU += &let { + proc: bool = $context.connection.proc_set_request(this); +}; +refine typeattr TrapPDU += &let { + proc: bool = $context.connection.proc_trap(this); +}; +refine typeattr GetBulkRequestPDU += &let { + proc: bool = $context.connection.proc_get_bulk_request(this); +}; +refine typeattr InformRequestPDU += &let { + proc: bool = $context.connection.proc_inform_request(this); +}; +refine typeattr v2TrapPDU += &let { + proc: bool = $context.connection.proc_v2_trap(this); +}; +refine typeattr ReportPDU += &let { + proc: bool = $context.connection.proc_report(this); +}; + +refine typeattr UnknownVersionHeader += &let { + proc: bool = $context.connection.proc_unknown_version_header(this); +}; +refine typeattr UnknownPDU += &let { + proc: bool = $context.connection.proc_unknown_pdu(this); +}; +refine typeattr UnknownScopedPDU += &let { + proc: bool = $context.connection.proc_unknown_scoped_pdu(this); +}; +refine typeattr EncryptedPDU += &let { + proc: bool = $context.connection.proc_encrypted_pdu(this); +}; + +refine typeattr Header += &let { + proc: bool = $context.connection.proc_header(this); +}; + +refine typeattr v3HeaderData += &let { + proc: bool = $context.connection.proc_v3_header_data(this); +}; + +refine typeattr NetworkAddress += &let { + valid: bool = $context.connection.check_tag(encoding.meta, + APP_IPADDRESS_TAG); +}; +refine typeattr TimeTicks += &let { + valid: bool = $context.connection.check_tag(asn1_integer.meta, + APP_TIMETICKS_TAG); +}; + +refine typeattr ASN1SequenceMeta += &let { + valid: bool = $context.connection.check_tag(encoding, + ASN1_SEQUENCE_TAG); +}; +refine typeattr ASN1Integer += &let { + valid: bool = $context.connection.check_int(this); +}; +refine typeattr ASN1OctetString += &let { + valid: bool = $context.connection.check_tag(encoding.meta, + ASN1_OCTET_STRING_TAG); +}; +refine typeattr ASN1ObjectIdentifier += &let { + valid: bool = $context.connection.check_tag(encoding.meta, + ASN1_OBJECT_IDENTIFIER_TAG); +}; diff --git a/src/analyzer/protocol/snmp/snmp-protocol.pac b/src/analyzer/protocol/snmp/snmp-protocol.pac new file mode 100644 index 0000000000..8d9b602ea2 --- /dev/null +++ b/src/analyzer/protocol/snmp/snmp-protocol.pac @@ -0,0 +1,272 @@ +# SNMPv1: RFC 1157 +# SNMPv2: RFC 1901 and 3416 +# SNMPv3: RFC 3412 +# Variable Bindings use definitions from RFC 1155 (and 3416). +# +# The SNMP protocol uses a well-defined subset of ASN.1 with the +# Basic Encoding Rules (BER). Definite-length encodings are always +# used. Primitive or non-constructor encodings are preferred over +# constructor encodings. + +type TopLevelMessage(is_orig: bool) = record { + asn1_sequence_meta: ASN1SequenceMeta; + version: ASN1Integer; + header: Header(version_value, is_orig); + pdu_or_not: case have_plaintext_pdu(header) of { + false -> none: empty; + true -> pdu: PDU_Choice(header); + }; +} &let { + version_value: int64 = binary_to_int64(version.encoding.content); +}; + +############################## SNMP Header Versions + +enum SNMP_VersionTag { + SNMPV1_TAG = 0, + SNMPV2_TAG = 1, + SNMPV3_TAG = 3, +}; + +type Header(version: int64, is_orig: bool) = case version of { + SNMPV1_TAG -> v1: v1Header(this); + SNMPV2_TAG -> v2: v2Header(this); + SNMPV3_TAG -> v3: v3Header(this); + default -> unknown: UnknownVersionHeader(this); +}; + +function have_plaintext_pdu(header: Header): bool = + case header.version of { + SNMPV1_TAG -> true; + SNMPV2_TAG -> true; + SNMPV3_TAG -> header.v3.next.tag == ASN1_SEQUENCE_TAG; + default -> false; + }; + +type PDU_Choice(header: Header) = record { + choice: ASN1EncodingMeta; + pdu: PDU(choice.tag, header); +}; + +type PDU(choice: uint8, header: Header) = case choice of { + default -> unknown: UnknownPDU(choice, header); +}; + +refine casetype PDU += { + # PDU choices from RFC 1157. + 0xa0 -> get_request: GetRequestPDU(header); + 0xa1 -> get_next_request: GetNextRequestPDU(header); + 0xa2 -> response: ResponsePDU(header); + 0xa3 -> set_request: SetRequestPDU(header); + 0xa4 -> trap: TrapPDU(header); +}; + +refine casetype PDU += { + # PDU choices from RFC 3416. + 0xa5 -> get_bulk_request: GetBulkRequestPDU(header); + 0xa6 -> inform_request: InformRequestPDU(header); + 0xa7 -> v2_trap: v2TrapPDU(header); + 0xa8 -> report: ReportPDU(header); +}; + +type v1Header(header: Header) = record { + community: ASN1OctetString; +}; + +type v2Header(header: Header) = record { + community: ASN1OctetString; +}; + +type v3Header(header: Header) = record { + global_data: v3HeaderData; + security_parameters: ASN1OctetString; + next: ASN1EncodingMeta; + scoped_pdu_data: case next.tag of { + ASN1_SEQUENCE_TAG -> plaintext_pdu: v3ScopedPDU; + ASN1_OCTET_STRING_TAG -> encrypted_pdu: EncryptedPDU(header); + default -> unknown_pdu: UnknownScopedPDU(next.tag, + header); + }; +}; + +type v3HeaderData = record { + asn1_sequence_meta: ASN1SequenceMeta; + id: ASN1Integer; + max_size: ASN1Integer; + flags: ASN1OctetString; + security_model: ASN1Integer; +}; + +type v3ScopedPDU = record { + context_engine_id: ASN1OctetString; + context_name: ASN1OctetString; +}; + +type EncryptedPDU(header: Header) = record { + data: bytestring &restofdata &transient; +}; + +type UnknownScopedPDU(tag: uint8, header: Header) = record { + data: bytestring &restofdata &transient; +}; + +type UnknownVersionHeader(header: Header) = record { + data: bytestring &restofdata &transient; +}; + +############################## SNMP PDUs + +type CommonPDU(header: Header) = record { + request_id: ASN1Integer; + error_status: ASN1Integer; + error_index: ASN1Integer; + var_bindings: VarBindList; +}; + +type GetRequestPDU(header: Header) = record { + pdu: CommonPDU(header); +}; + +type GetNextRequestPDU(header: Header) = record { + pdu: CommonPDU(header); +}; + +type ResponsePDU(header: Header) = record { + pdu: CommonPDU(header); +}; + +type SetRequestPDU(header: Header) = record { + pdu: CommonPDU(header); +}; + +type TrapPDU(header: Header) = record { + enterprise: ASN1ObjectIdentifier; + agent_addr: NetworkAddress; + generic_trap: ASN1Integer; + specific_trap: ASN1Integer; + time_stamp: TimeTicks; + var_bindings: VarBindList; +}; + +type GetBulkRequestPDU(header: Header) = record { + request_id: ASN1Integer; + non_repeaters: ASN1Integer; + max_repititions: ASN1Integer; + var_bindings: VarBindList; +}; + +type InformRequestPDU(header: Header) = record { + pdu: CommonPDU(header); +}; + +type v2TrapPDU(header: Header) = record { + pdu: CommonPDU(header); +}; + +type ReportPDU(header: Header) = record { + pdu: CommonPDU(header); +}; + +type UnknownPDU(tag: uint8, header: Header) = record { + data: bytestring &restofdata &transient; +}; + +type VarBindList = record { + asn1_sequence_meta: ASN1SequenceMeta; + bindings: VarBind[]; +}; + +type VarBind = record { + asn1_sequence_meta: ASN1SequenceMeta; + name: ObjectName; + value: ObjectSyntax; +}; + +############################## Variable Binding Encodings (RFC 1155 and 3416) + +type ObjectName = record { + oid: ASN1ObjectIdentifier; +}; + +type ObjectSyntax = record { + encoding: ASN1Encoding; # The tag may be a CHOICE among several; +}; + +type NetworkAddress = record { + encoding: ASN1Encoding; +}; + +type TimeTicks = record { + asn1_integer: ASN1Encoding; +}; + +enum AppSyntaxTypeTag { + APP_IPADDRESS_TAG = 0x40, + APP_COUNTER32_TAG = 0x41, + APP_UNSIGNED32_TAG = 0x42, + APP_TIMETICKS_TAG = 0x43, + APP_OPAQUE_TAG = 0x44, + APP_COUNTER64_TAG = 0x46, +}; + +enum VarBindNullTag { + VARBIND_UNSPECIFIED_TAG = 0x05, + VARBIND_NOSUCHOBJECT_TAG = 0x80, + VARBIND_NOSUCHINSTANCE_TAG = 0x81, + VARBIND_ENDOFMIBVIEW_TAG = 0x82, +}; + +############################## ASN.1 Encodings + +enum ASN1TypeTag { + ASN1_INTEGER_TAG = 0x02, + ASN1_OCTET_STRING_TAG = 0x04, + ASN1_NULL_TAG = 0x05, + ASN1_OBJECT_IDENTIFIER_TAG = 0x06, + ASN1_SEQUENCE_TAG = 0x30, +}; + +type ASN1Encoding = record { + meta: ASN1EncodingMeta; + content: bytestring &length = meta.length; +}; + +type ASN1EncodingMeta = record { + tag: uint8; + len: uint8; + more_len: bytestring &length = long_len ? len & 0x7f : 0; +} &let { + long_len: bool = len & 0x80; + length: uint64 = long_len ? binary_to_int64(more_len) : len & 0x7f; +}; + +type ASN1SequenceMeta = record { + encoding: ASN1EncodingMeta; +}; + +type ASN1Integer = record { + encoding: ASN1Encoding; +}; + +type ASN1OctetString = record { + encoding: ASN1Encoding; +}; + +type ASN1ObjectIdentifier = record { + encoding: ASN1Encoding; +}; + +############################## ASN.1 Conversion Functions + +function binary_to_int64(bs: bytestring): int64 + %{ + int64 rval = 0; + + for ( int i = 0; i < bs.length(); ++i ) + { + uint64 byte = bs[i]; + rval |= byte << (8 * (bs.length() - (i + 1))); + } + + return rval; + %} diff --git a/src/analyzer/protocol/snmp/snmp.pac b/src/analyzer/protocol/snmp/snmp.pac new file mode 100644 index 0000000000..29b9d32e73 --- /dev/null +++ b/src/analyzer/protocol/snmp/snmp.pac @@ -0,0 +1,25 @@ +%include binpac.pac +%include bro.pac + +%extern{ +#include "types.bif.h" +#include "events.bif.h" +%} + +analyzer SNMP withcontext { + connection: SNMP_Conn; + flow: SNMP_Flow; +}; + +connection SNMP_Conn(bro_analyzer: BroAnalyzer) { + upflow = SNMP_Flow(true); + downflow = SNMP_Flow(false); +}; + +%include snmp-protocol.pac + +flow SNMP_Flow(is_orig: bool) { + datagram = TopLevelMessage(is_orig) withcontext(connection, this); +}; + +%include snmp-analyzer.pac diff --git a/src/analyzer/protocol/snmp/types.bif b/src/analyzer/protocol/snmp/types.bif new file mode 100644 index 0000000000..40d995284d --- /dev/null +++ b/src/analyzer/protocol/snmp/types.bif @@ -0,0 +1,18 @@ + +module SNMP; + +type Header: record; +type HeaderV1: record; +type HeaderV2: record; +type HeaderV3: record; + +type PDU: record; +type TrapPDU: record; +type BulkPDU: record; +type ScopedPDU_Context: record; + +type ObjectValue: record; +type Binding: record; +type Bindings: vector; + +module GLOBAL; diff --git a/testing/btest/Baseline/core.print-bpf-filters/output2 b/testing/btest/Baseline/core.print-bpf-filters/output2 index daa23f3b7a..f2825e6cb8 100644 --- a/testing/btest/Baseline/core.print-bpf-filters/output2 +++ b/testing/btest/Baseline/core.print-bpf-filters/output2 @@ -1,5 +1,7 @@ 2 1080 1 137 +1 161 +1 162 1 20000 1 21 1 2123 @@ -39,8 +41,8 @@ 1 992 1 993 1 995 -43 and -42 or -43 port +45 and +44 or +45 port 32 tcp -11 udp +13 udp diff --git a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log index 0218611d1c..6828e6aa58 100644 --- a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log @@ -3,7 +3,7 @@ #empty_field (empty) #unset_field - #path loaded_scripts -#open 2013-10-30-16-52-11 +#open 2014-02-18-18-10-43 #fields name #types string scripts/base/init-bare.bro @@ -12,6 +12,7 @@ scripts/base/init-bare.bro build/scripts/base/bif/strings.bif.bro build/scripts/base/bif/bro.bif.bro build/scripts/base/bif/reporter.bif.bro + build/scripts/base/bif/plugins/Bro_SNMP.types.bif.bro build/scripts/base/bif/event.bif.bro build/scripts/base/bif/plugins/__load__.bro build/scripts/base/bif/plugins/Bro_ARP.events.bif.bro @@ -53,6 +54,7 @@ scripts/base/init-bare.bro build/scripts/base/bif/plugins/Bro_SMB.events.bif.bro build/scripts/base/bif/plugins/Bro_SMTP.events.bif.bro build/scripts/base/bif/plugins/Bro_SMTP.functions.bif.bro + build/scripts/base/bif/plugins/Bro_SNMP.events.bif.bro build/scripts/base/bif/plugins/Bro_SOCKS.events.bif.bro build/scripts/base/bif/plugins/Bro_SSH.events.bif.bro build/scripts/base/bif/plugins/Bro_SSL.events.bif.bro @@ -101,4 +103,4 @@ scripts/base/init-bare.bro build/scripts/base/bif/top-k.bif.bro scripts/policy/misc/loaded-scripts.bro scripts/base/utils/paths.bro -#close 2013-10-30-16-52-11 +#close 2014-02-18-18-10-43 diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 76b3f3a596..5d32b25823 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -3,7 +3,7 @@ #empty_field (empty) #unset_field - #path loaded_scripts -#open 2014-01-31-22-54-38 +#open 2014-02-18-18-10-44 #fields name #types string scripts/base/init-bare.bro @@ -12,6 +12,7 @@ scripts/base/init-bare.bro build/scripts/base/bif/strings.bif.bro build/scripts/base/bif/bro.bif.bro build/scripts/base/bif/reporter.bif.bro + build/scripts/base/bif/plugins/Bro_SNMP.types.bif.bro build/scripts/base/bif/event.bif.bro build/scripts/base/bif/plugins/__load__.bro build/scripts/base/bif/plugins/Bro_ARP.events.bif.bro @@ -53,6 +54,7 @@ scripts/base/init-bare.bro build/scripts/base/bif/plugins/Bro_SMB.events.bif.bro build/scripts/base/bif/plugins/Bro_SMTP.events.bif.bro build/scripts/base/bif/plugins/Bro_SMTP.functions.bif.bro + build/scripts/base/bif/plugins/Bro_SNMP.events.bif.bro build/scripts/base/bif/plugins/Bro_SOCKS.events.bif.bro build/scripts/base/bif/plugins/Bro_SSH.events.bif.bro build/scripts/base/bif/plugins/Bro_SSL.events.bif.bro @@ -200,6 +202,8 @@ scripts/base/init-default.bro scripts/base/protocols/modbus/consts.bro scripts/base/protocols/modbus/main.bro scripts/base/protocols/pop3/__load__.bro + scripts/base/protocols/snmp/__load__.bro + scripts/base/protocols/snmp/main.bro scripts/base/protocols/smtp/__load__.bro scripts/base/protocols/smtp/main.bro scripts/base/protocols/smtp/entities.bro @@ -222,4 +226,4 @@ scripts/base/init-default.bro scripts/base/misc/find-checksum-offloading.bro scripts/base/misc/find-filtered-trace.bro scripts/policy/misc/loaded-scripts.bro -#close 2014-01-31-22-54-38 +#close 2014-02-18-18-10-44 diff --git a/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out1 b/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out1 new file mode 100644 index 0000000000..f564ee0c62 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out1 @@ -0,0 +1,598 @@ +snmp_get_request + [orig_h=172.31.19.54, orig_p=15916/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 38 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.2.0 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15916/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 38 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.2.0 + value (tag=0x06): 1.3.6.1.4.1.2001.1.1.1.297.93.1.27.2.2.1 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15917/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 39 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.5.0 + value (tag=0x05): + oid: 1.3.6.1.2.1.1.6.0 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15917/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 39 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.5.0 + value (tag=0x04): B6300 + oid: 1.3.6.1.2.1.1.6.0 + value (tag=0x04): Chandra's cube +snmp_get_request + [orig_h=172.31.19.54, orig_p=15918/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 40 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.2.2.1.6.1 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15918/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 40 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.2.2.1.6.1 + value (tag=0x04): ^H\07^U\xe6\xbc +snmp_get_request + [orig_h=172.31.19.54, orig_p=15919/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 41 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130104 + value (tag=0x05): + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130102 + value (tag=0x05): + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14130400 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15919/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 41 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130104 + value (tag=0x04): 172.31.19.2 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130102 + value (tag=0x04): 255.255.255.0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14130400 + value (tag=0x02): 1 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15920/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 42 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.43.14.1.1.6.1.5 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15920/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 42 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.43.14.1.1.6.1.5 + value (tag=0x02): 3 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15921/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 43 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14150900 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15921/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 43 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14150900 + value (tag=0x02): 1 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15922/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 44 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.2.0 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15922/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 44 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.2.0 + value (tag=0x06): 1.3.6.1.4.1.2001.1.1.1.297.93.1.27.2.2.1 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15923/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 45 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.5.0 + value (tag=0x05): + oid: 1.3.6.1.2.1.1.6.0 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15923/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 45 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.5.0 + value (tag=0x04): B6300 + oid: 1.3.6.1.2.1.1.6.0 + value (tag=0x04): Chandra's cube +snmp_get_request + [orig_h=172.31.19.54, orig_p=15924/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 46 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.2.2.1.6.1 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15924/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 46 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.2.2.1.6.1 + value (tag=0x04): ^H\07^U\xe6\xbc +snmp_get_request + [orig_h=172.31.19.54, orig_p=15925/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 47 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130104 + value (tag=0x05): + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130102 + value (tag=0x05): + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14130400 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15925/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 47 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130104 + value (tag=0x04): 172.31.19.2 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130102 + value (tag=0x04): 255.255.255.0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14130400 + value (tag=0x02): 1 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15926/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 48 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.43.14.1.1.6.1.5 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15926/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 48 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.43.14.1.1.6.1.5 + value (tag=0x02): 3 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15927/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 49 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14150900 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15927/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 49 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14150900 + value (tag=0x02): 1 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15928/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 50 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.2.0 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15928/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 50 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.2.0 + value (tag=0x06): 1.3.6.1.4.1.2001.1.1.1.297.93.1.27.2.2.1 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15929/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 51 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.5.0 + value (tag=0x05): + oid: 1.3.6.1.2.1.1.6.0 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15929/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 51 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.5.0 + value (tag=0x04): B6300 + oid: 1.3.6.1.2.1.1.6.0 + value (tag=0x04): Chandra's cube +snmp_get_request + [orig_h=172.31.19.54, orig_p=15930/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 52 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.2.2.1.6.1 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15930/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 52 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.2.2.1.6.1 + value (tag=0x04): ^H\07^U\xe6\xbc +snmp_get_request + [orig_h=172.31.19.54, orig_p=15931/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 53 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130104 + value (tag=0x05): + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130102 + value (tag=0x05): + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14130400 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15931/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 53 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130104 + value (tag=0x04): 172.31.19.2 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.7.10.14130102 + value (tag=0x04): 255.255.255.0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14130400 + value (tag=0x02): 1 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15932/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 54 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.43.14.1.1.6.1.5 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15932/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 54 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.43.14.1.1.6.1.5 + value (tag=0x02): 3 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15933/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 55 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14150900 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15933/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 55 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.64.4.2.1.5.10.14150900 + value (tag=0x02): 1 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15934/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 56 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.2.0 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15934/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 56 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.2.0 + value (tag=0x06): 1.3.6.1.4.1.2001.1.1.1.297.93.1.27.2.2.1 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15935/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 57 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.8.1.3.0 + value (tag=0x05): + oid: 1.3.6.1.4.1.253.8.51.8.1.1.0 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15935/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 57 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.8.1.3.0 + value (tag=0x02): 0 + oid: 1.3.6.1.4.1.253.8.51.8.1.1.0 + value (tag=0x02): 300 +snmp_set_request + [orig_h=172.31.19.54, orig_p=15936/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 58 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.8.2.1.2.1 + value (tag=0x02): 4 + oid: 1.3.6.1.4.1.253.8.51.8.2.1.3.1 + value (tag=0x04): FujiXeroxExodus + oid: 1.3.6.1.4.1.253.8.51.8.2.1.4.1 + value (tag=0x06): 1.3.6.1.4.1.253.8.51.8.2 + oid: 1.3.6.1.4.1.253.8.51.8.2.1.5.1 + value (tag=0x02): 300 +snmp_response + [orig_h=172.31.19.54, orig_p=15936/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 58 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.8.2.1.2.1 + value (tag=0x02): 4 + oid: 1.3.6.1.4.1.253.8.51.8.2.1.3.1 + value (tag=0x04): FujiXeroxExodus + oid: 1.3.6.1.4.1.253.8.51.8.2.1.4.1 + value (tag=0x06): 1.3.6.1.4.1.253.8.51.8.2 + oid: 1.3.6.1.4.1.253.8.51.8.2.1.5.1 + value (tag=0x02): 300 +snmp_set_request + [orig_h=172.31.19.54, orig_p=15937/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 59 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.2.10.1 + value (tag=0x02): 6 +snmp_response + [orig_h=172.31.19.54, orig_p=15937/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 59 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.2.10.1 + value (tag=0x02): 6 +snmp_set_request + [orig_h=172.31.19.54, orig_p=15938/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 60 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.10.2.1.7.10.14130101 + value (tag=0x04): 172.31.19.73 + oid: 1.3.6.1.4.1.253.8.51.10.2.1.5.10.14130400 + value (tag=0x02): 2 + oid: 1.3.6.1.4.1.253.8.51.10.2.1.7.10.14130102 + value (tag=0x04): 255.255.255.0 + oid: 1.3.6.1.4.1.253.8.51.10.2.1.7.10.14130104 + value (tag=0x04): 172.31.19.2 +snmp_response + [orig_h=172.31.19.54, orig_p=15938/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 60 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.10.2.1.7.10.14130101 + value (tag=0x04): 172.31.19.73 + oid: 1.3.6.1.4.1.253.8.51.10.2.1.5.10.14130400 + value (tag=0x02): 2 + oid: 1.3.6.1.4.1.253.8.51.10.2.1.7.10.14130102 + value (tag=0x04): 255.255.255.0 + oid: 1.3.6.1.4.1.253.8.51.10.2.1.7.10.14130104 + value (tag=0x04): 172.31.19.2 +snmp_set_request + [orig_h=172.31.19.54, orig_p=15939/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 61 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.2.10.1 + value (tag=0x02): 4 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.4.10.1 + value (tag=0x02): 4 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.3.10.1 + value (tag=0x02): 10 +snmp_response + [orig_h=172.31.19.54, orig_p=15939/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 61 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.2.10.1 + value (tag=0x02): 4 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.4.10.1 + value (tag=0x02): 4 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.3.10.1 + value (tag=0x02): 10 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15940/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 62 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.5.10.1 + value (tag=0x05): + oid: 1.3.6.1.4.1.253.8.51.9.2.1.6.10.1 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15940/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 62 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.5.10.1 + value (tag=0x02): 0 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.6.10.1 + value (tag=0x02): 0 +snmp_set_request + [orig_h=172.31.19.54, orig_p=15941/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 63 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.4.10.1 + value (tag=0x02): 8 +snmp_response + [orig_h=172.31.19.54, orig_p=15941/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 63 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.4.1.253.8.51.9.2.1.4.10.1 + value (tag=0x02): 8 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15942/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 64 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.3.0 + value (tag=0x05): +snmp_get_request + [orig_h=172.31.19.54, orig_p=15945/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 65 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.3.0 + value (tag=0x05): +snmp_get_request + [orig_h=172.31.19.54, orig_p=15952/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 66 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.3.0 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15952/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 66 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.3.0 + value (tag=0x43): 300 +snmp_get_request + [orig_h=172.31.19.54, orig_p=15953/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 67 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.2.0 + value (tag=0x05): +snmp_response + [orig_h=172.31.19.54, orig_p=15953/udp, resp_h=172.31.19.73, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 67 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.2.0 + value (tag=0x06): 1.3.6.1.4.1.2001.1.1.1.297.93.1.27.2.2.1 diff --git a/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out2 b/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out2 new file mode 100644 index 0000000000..743f18bbf1 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out2 @@ -0,0 +1,26 @@ +snmp_get_request + [orig_h=203.143.168.235, orig_p=1026/udp, resp_h=129.94.135.39, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 1567 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.25.3.2.1.5.1 + value (tag=0x05): + oid: 1.3.6.1.2.1.25.3.5.1.1.1 + value (tag=0x05): + oid: 1.3.6.1.2.1.25.3.5.1.2.1 + value (tag=0x05): +snmp_response + [orig_h=203.143.168.235, orig_p=1026/udp, resp_h=129.94.135.39, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 1567 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.25.3.2.1.5.1 + value (tag=0x02): 5 + oid: 1.3.6.1.2.1.25.3.5.1.1.1 + value (tag=0x02): 1 + oid: 1.3.6.1.2.1.25.3.5.1.2.1 + value (tag=0x04): \xc0 diff --git a/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out3 b/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out3 new file mode 100644 index 0000000000..b8319b67ec --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out3 @@ -0,0 +1,18 @@ +snmp_set_request + [orig_h=127.0.0.1, orig_p=63034/udp, resp_h=127.0.0.1, resp_p=161/udp] + is_orig: T + [community=] + request_id: 2064150121 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.5.0 + value (tag=0x04): musec +snmp_response + [orig_h=127.0.0.1, orig_p=63034/udp, resp_h=127.0.0.1, resp_p=161/udp] + is_orig: F + [community=] + request_id: 2064150121 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.5.0 + value (tag=0x05): diff --git a/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out4 b/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out4 new file mode 100644 index 0000000000..0854c7096c --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.snmp.v1/out4 @@ -0,0 +1,11 @@ +snmp_trap + [orig_h=127.0.0.1, orig_p=57150/udp, resp_h=127.0.0.1, resp_p=162/udp] + is_orig: T + [community=public] + enterprise: 1.3.6.1.4.1.31337.0 + agent: 1.0.0.127 + generic_trap: 0 + specific_trap: 0 + time_stamp: 0 + oid: 1.3.6.1.2.1.2.1.0 + value (tag=0x02): 33 diff --git a/testing/btest/Baseline/scripts.base.protocols.snmp.v2/out1 b/testing/btest/Baseline/scripts.base.protocols.snmp.v2/out1 new file mode 100644 index 0000000000..cb18518552 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.snmp.v2/out1 @@ -0,0 +1,18 @@ +snmp_get_request + [orig_h=10.10.1.159, orig_p=51217/udp, resp_h=10.10.3.109, resp_p=161/udp] + is_orig: T + [community=public] + request_id: 895734538 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.2.2.1.17.1 + value (tag=0x05): +snmp_response + [orig_h=10.10.1.159, orig_p=51217/udp, resp_h=10.10.3.109, resp_p=161/udp] + is_orig: F + [community=public] + request_id: 895734538 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.2.2.1.17.1 + value (tag=0x41): 854387 diff --git a/testing/btest/Baseline/scripts.base.protocols.snmp.v2/out2 b/testing/btest/Baseline/scripts.base.protocols.snmp.v2/out2 new file mode 100644 index 0000000000..0c1971c9f5 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.snmp.v2/out2 @@ -0,0 +1,18 @@ +snmp_get_bulk_request + [orig_h=127.0.0.1, orig_p=28456/udp, resp_h=127.0.0.1, resp_p=161/udp] + is_orig: T + [community=] + request_id: 1817072941 + non_repeaters: 0 + max_repititions: 0 + oid: 1.3.6.1.2.1.1.5.0 + value (tag=0x05): +snmp_response + [orig_h=127.0.0.1, orig_p=28456/udp, resp_h=127.0.0.1, resp_p=161/udp] + is_orig: F + [community=] + request_id: 1817072941 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.5.0 + value (tag=0x05): diff --git a/testing/btest/Baseline/scripts.base.protocols.snmp.v2/out3 b/testing/btest/Baseline/scripts.base.protocols.snmp.v2/out3 new file mode 100644 index 0000000000..4abbb8f819 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.snmp.v2/out3 @@ -0,0 +1,72 @@ +snmp_get_request + [orig_h=10.144.246.184, orig_p=33938/udp, resp_h=10.144.246.161, resp_p=161/udp] + is_orig: T + [community=[R0_C@cti!]] + request_id: 722681733 + error_stat: 0 + error_idx: 0 + oid: 0.1 + value (tag=0x05): +snmp_response + [orig_h=10.144.246.184, orig_p=33938/udp, resp_h=10.144.246.161, resp_p=161/udp] + is_orig: F + [community=[R0_C@cti!]] + request_id: 722681733 + error_stat: 0 + error_idx: 0 + oid: 1.0.8802.1.1.1.1.1.1.0 + value (tag=0x02): 2 +snmp_get_request + [orig_h=10.144.246.184, orig_p=43824/udp, resp_h=10.144.246.161, resp_p=161/udp] + is_orig: T + [community=[R0_C@cti!]] + request_id: 555232471 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.3.0 + value (tag=0x05): +snmp_response + [orig_h=10.144.246.184, orig_p=43824/udp, resp_h=10.144.246.161, resp_p=161/udp] + is_orig: F + [community=[R0_C@cti!]] + request_id: 555232471 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.3.0 + value (tag=0x43): 76705700 +snmp_get_request + [orig_h=10.144.246.184, orig_p=40807/udp, resp_h=10.144.246.161, resp_p=161/udp] + is_orig: T + [community=[R0_C@cti!]] + request_id: 349867006 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.31.1.1.1.10.1 + value (tag=0x05): +snmp_response + [orig_h=10.144.246.184, orig_p=40807/udp, resp_h=10.144.246.161, resp_p=161/udp] + is_orig: F + [community=[R0_C@cti!]] + request_id: 349867006 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.31.1.1.1.10.1 + value (tag=0x46): 2232821312 +snmp_get_request + [orig_h=10.144.246.184, orig_p=54059/udp, resp_h=10.144.246.161, resp_p=161/udp] + is_orig: T + [community=[R0_C@cti!]] + request_id: 107891391 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.31.1.1.1.6.1 + value (tag=0x05): +snmp_response + [orig_h=10.144.246.184, orig_p=54059/udp, resp_h=10.144.246.161, resp_p=161/udp] + is_orig: F + [community=[R0_C@cti!]] + request_id: 107891391 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.31.1.1.1.6.1 + value (tag=0x46): 12606463906 diff --git a/testing/btest/Baseline/scripts.base.protocols.snmp.v3/out1 b/testing/btest/Baseline/scripts.base.protocols.snmp.v3/out1 new file mode 100644 index 0000000000..20f6d45ab0 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.snmp.v3/out1 @@ -0,0 +1,34 @@ +snmp_get_request + [orig_h=127.0.0.1, orig_p=54211/udp, resp_h=127.0.0.1, resp_p=161/udp] + is_orig: T + [id=544943986, max_size=16384, flags=4, auth_flag=F, priv_flag=F, reportable_flag=T, security_model=3, security_params=0^N^D\0^B^A*^B^A*^D\0^D\0^D\0, pdu_context=[engine_id=, name=]] + request_id: 544943986 + error_stat: 0 + error_idx: 0 +snmp_report + [orig_h=127.0.0.1, orig_p=54211/udp, resp_h=127.0.0.1, resp_p=161/udp] + is_orig: F + [id=544943986, max_size=16384, flags=0, auth_flag=F, priv_flag=F, reportable_flag=F, security_model=3, security_params=0\x1b^D^M\x80\0\x1f\x88\x80\xa9I\x8e^:,0C^B^A\xdd^B^A\xdd^D\0^D\0^D\0, pdu_context=[engine_id=\x80\0\x1f\x88\x80\xa9I\x8e^:,0C, name=]] + request_id: 544943986 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.6.3.15.1.1.0 + value (tag=0x41): 3 +snmp_get_request + [orig_h=127.0.0.1, orig_p=54211/udp, resp_h=127.0.0.1, resp_p=161/udp] + is_orig: T + [id=544943986, max_size=16384, flags=4, auth_flag=F, priv_flag=F, reportable_flag=T, security_model=3, security_params=0/^D^M\x80\0\x1f\x88\x80\xa9I\x8e^:,0C^B^A\xdd^B^A\xdd^D^Husername^D^L\0\0\0\0\0\0\0\0\0\0\0\0^D\0, pdu_context=[engine_id=\x80\0\x1f\x88\x80\xa9I\x8e^:,0C, name=]] + request_id: 544943986 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.6.0 + value (tag=0x05): +snmp_response + [orig_h=127.0.0.1, orig_p=54211/udp, resp_h=127.0.0.1, resp_p=161/udp] + is_orig: F + [id=544943986, max_size=16384, flags=0, auth_flag=F, priv_flag=F, reportable_flag=F, security_model=3, security_params=0#^D^M\x80\0\x1f\x88\x80\xa9I\x8e^:,0C^B^A\xdd^B^A\xdd^D^Husername^D\0^D\0, pdu_context=[engine_id=\x80\0\x1f\x88\x80\xa9I\x8e^:,0C, name=]] + request_id: 544943986 + error_stat: 0 + error_idx: 0 + oid: 1.3.6.1.2.1.1.6.0 + value (tag=0x04): diff --git a/testing/btest/Traces/snmp/snmpv1_get.pcap b/testing/btest/Traces/snmp/snmpv1_get.pcap new file mode 100644 index 0000000000000000000000000000000000000000..de8505b529dde4a6bf171e462a9799627fca7da1 GIT binary patch literal 7165 zcmd6sZE#f89mdbSxw-61j0Rd-7K1@37!o!oyV=c>z$V#*NF)J50UahPFUg205o)AO z?Wo5ojs(~!o=(kuHt7h3Es^<*b=Up*6g{0(*fD5i?wjB#Ng?0l zD>U#0zJfg)T9$EW*f5OmHr{H?H%)`6KFkN$Hpo#^s5TZNg6dU|YB{LV(?h&X(#$P2 z4P1iiTA!*KRQ@O1VSM*wfK5V+n!-31xmGYfFEK7>!%zQ!-ze$jJAAzsUgt7aGpjn2 zjC0N-?k$^HwY|Hx-!*#o_N9{zJNNAvBjj(t7GRs8PEA4XFTiFL@=Xsp3gnpeB)>uG zLT4e_G&(eE_*`eGWbX@fTc$B9 zbl}|=Qz&Jn`$_eFHNJmxThWETeh^^KqF>Y$7mh?02p8^^TxenY|DNODlKPh4?e}dv zUs$PcR=Bl27LB(?TUSJ5d{Kq3B(1AriA2k6mo_`OU}m&Vr%#^)r)IMVo#lE$vyzmvva8w%>u7&Zg>bq~1> z$T91HlE##rxGJad!Qr4TjTb2+vkhrHt)#K5p-JP@BSBpn!%)y1@@NvE8UOgAlEy6# z%@s}K#%~05X}nmtaF0~%1k(7hlE!Y|{yS-0pAG8L7^Q=uuX%=IRfIIoC}~WAM#E!< zG|oO4)TQxPgf*{7)+CX}9ZDLzDl?_=`;TeU7!@d)-tBj3A*f#Ts8)a~J)Ka}IPOqs(^xS6Hl$1AWr8s$ zF|I%w?^n{;)%#b|n7Yt^Hl$1Ar2_eP9&!heW7fS&8q@ZGMyRqjCXJytLb^0=5}5Lf zwF7CKRnpkim?4cx=^uXx>C*THL37Zf=>*OA#~&(boN#EaSQ=B`?)WIAOXFtY!fvV9 zok-(Hlr(nx_McB<>h!G7Lb^1@EX0hU9cpo&uY{p(7n4dFCmlm8q%o;%VqskxFBjIF zl&o2aG>$51?5b2sW0IK+hjnXXOt+Hhy$UcL7j99~xZQ!7F^x&9e{NW}HjWCU6B5!Y zr11tNja@B$8lP_n>(Uq#3}CbnFIFiHFkX{Y(wNQ_aFw4_5YG6bur7^T1WrN1Nh6I1 zlr(k~E-Q`KN5gC!I}2*cR%WDt2?MI1dQ@GYT61uWr-9&|zu;}Q!l7D%9n)3fOavR< zc)+NlzGuF1FTup7%(~d8C!A+{kB_DU-`{O76jV z(`Y8~A9jY>3FuN&u%9VlG64HF54#)KkFWiJXCIQ(k58Ef4oyTgC!kd8bDKDTG7Sqm z>yn#QhIMuSzVSP68M}MW)at1{qx&X#ed$*$!wyT&!3jml6RHiD;NdQxK(X(cNUN}K zt29`;+2ey{1o{6d!K|CY-WyA)!C(Qi7d3dnt3eNHklK_ld1D>NX-=n80(xUz?O7K@ z0Ya#OP1SB5@|6^?1|u=y)h{KldZ2W?M2XIgE<@?`&0%&9V~U!>bgFq1Va@mGVW0h02OvSNimEW~!gerHd=x%5W93N;5dc9H{pNg~z$M;K)_o7#8N_v&Q z^1b>|TaeuapQtHbZ7U#o;MLQfSAFnma8HtFB(HKq(7HPS3^lX?Y@N4 zH=#8AvY}hrU}l4f_6|j+elYRy*OjGBx5FfDH0k~S02I1!*B&gc5(@MKMNwfuC`>2{ zJ(U$6fx_QTX&GJ+3iR}%!Umx*rYO)T#U(G#h=CNwUopI0oKlZ|8^`h8b)WP}_1M5- zXP1@i;_~=~!&RVNobyvv73;;igfz@^T8du@iiAfoOcXUc6$(7AoPvH1BZUXvG&GA$ X`zL}TE>R3)k=djyGF^pBE;9cK##mi- literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/snmp/snmpv1_get_short.pcap b/testing/btest/Traces/snmp/snmpv1_get_short.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a765af6640a64c2e590c8f2be4db96d753fea29f GIT binary patch literal 299 zcmca|c+)~A1{MYw`2U}Qff2~5zsT*f_6-+91&|HG4BWRTi={B|h8bVs;9ziNV90Vg z#K6!XSaINV|BBa*aqa3XObiPd!iwY!e3%#+Sl9|mlX5bX7uYi~vB?7kfXKkufS-+9 zn~jl)QIeU7k(H5^0ZD+Bkr7=0s0Qqg$DgqQoZ5Fi_b*;rYanHU+Fm|0laI2c?R7~DXr z90aSE)&n(w@HZ=lg$za-yapOfj6eeyD>AWEbL3?LIY49}Y#_+Sq0Pn!G=r6ag*CUd zI5in$$AwEQ4E{iqKp0{=#3ryEj!-*R!R%mI2((34Ji$O2Y{w!Q6g&6~co255G5`Sh CZXtI7 literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/snmp/snmpv1_trap.pcap b/testing/btest/Traces/snmp/snmpv1_trap.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e77219efd2efa7258ca4031a6d5f4e0195aa8d3c GIT binary patch literal 143 zcmca|c+)~A1{MYw`2U}Qff2|NSflI7X3WQs4rGHc8!HPl6C)!NGYcyl2ZJjELnKI* zgJAWfdY}dnzHi5{h{1K&Zv$&4Mg|tPg3_d%%;Y6{Y@FI`j4X_eUosgSSU~E4vOwev Sw$gy#fR~K}sDKF~tOx+r$`%6v literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/snmp/snmpv2_get.pcap b/testing/btest/Traces/snmp/snmpv2_get.pcap new file mode 100644 index 0000000000000000000000000000000000000000..705af973ba23bc1c199f3b836c797546f04abc52 GIT binary patch literal 233 zcmca|c+)~A1{MYw`2U}Qff2}=@si1V+dVdha3C9m86ATkgz z;A7*`W@BVxWMX0zWMl%2tzD@SO&Jn2WSb<8pS4%6(Fk^76L7@IH+o% Whh)tnMHFj<4Fr*`ab)J@ECv9V2r#Gs literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/snmp/snmpv2_get_bulk.pcap b/testing/btest/Traces/snmp/snmpv2_get_bulk.pcap new file mode 100644 index 0000000000000000000000000000000000000000..5099c7a3234abf655b516d2400d4c919511f3d6a GIT binary patch literal 214 zcmca|c+)~A1{MYw`2U}Qff2}guv*tsVJ|a-KadT=Y^*HIOpJ_7%q*;I91N}u42~dG z4uaLI>VXt?l?mjZ6JMAZqJZ{*Fou78p#D*Z`De8O&_5P`jvMHqTed)kiA7OD z=Q`9sd4PycNLr4(u%xgtvfp*?5#17@^y=NCCwr zAp-$~P0lPVlk%5<{Pi-A84-x+@#GKnmkP{Z^V5O;vfh<~8HfvjfhcmT`ybR_pg`mX z`%4}ej9kzdiz;PiNCNr_gfYAp!uKBRHGPEFfYv#%uQxEm@R|yWWnu;*D3-agGPH`R zIe@%( O9vh<@E7SY*_(cGDH`}EE literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/snmp/snmpv3_get_next.pcap b/testing/btest/Traces/snmp/snmpv3_get_next.pcap new file mode 100644 index 0000000000000000000000000000000000000000..13ed2e76462aaf1ddc8ad864be54851cfb64115e GIT binary patch literal 661 zcmaixy-EW?6ov21-W@g&cN3zbsKg)^{*fzK3Brm5NpB~LA}JJN5fzCk3@8!^h?QdJ z3W8#%kB~>uR`5;Yoyo3{UC?39Fu(VFocZj$1riXV*6jiaUVOhUl&^9g?DJep*=R{2 zq=mL}paig~Z~58A%{f2N`shFa>+L+PNMTV%;$)*(lhOwi$UB%J7eR_y?#PA+G^oc1 zH@qqM5XcyphCI0C@>)I1p1m<{g~of4F$8RVeCg3a!k9~1I6-4L(1d)e`BJ{#UY@5l zDZaRe6icx~gy%vZQjW4JHK&BKJRx9JXJzSl-iJMS;)PZso;%6Ae)eo5qBQYbq-Lm| zpfvF;QZWV+QaUF`mD=HMwSs9b`P(?Z_ydGsypPout1 +# @TEST-EXEC: bro -b -r $TRACES/snmp/snmpv1_get_short.pcap %INPUT $SCRIPTS/snmp-test.bro >out2 +# @TEST-EXEC: bro -b -r $TRACES/snmp/snmpv1_set.pcap %INPUT $SCRIPTS/snmp-test.bro >out3 +# @TEST-EXEC: bro -b -r $TRACES/snmp/snmpv1_trap.pcap %INPUT $SCRIPTS/snmp-test.bro >out4 + +# @TEST-EXEC: btest-diff out1 +# @TEST-EXEC: btest-diff out2 +# @TEST-EXEC: btest-diff out3 +# @TEST-EXEC: btest-diff out4 + +@load base/protocols/snmp diff --git a/testing/btest/scripts/base/protocols/snmp/v2.bro b/testing/btest/scripts/base/protocols/snmp/v2.bro new file mode 100644 index 0000000000..a2b9885fbb --- /dev/null +++ b/testing/btest/scripts/base/protocols/snmp/v2.bro @@ -0,0 +1,9 @@ +# @TEST-EXEC: bro -b -r $TRACES/snmp/snmpv2_get.pcap %INPUT $SCRIPTS/snmp-test.bro >out1 +# @TEST-EXEC: bro -b -r $TRACES/snmp/snmpv2_get_bulk.pcap %INPUT $SCRIPTS/snmp-test.bro >out2 +# @TEST-EXEC: bro -b -r $TRACES/snmp/snmpv2_get_next.pcap %INPUT $SCRIPTS/snmp-test.bro >out3 + +# @TEST-EXEC: btest-diff out1 +# @TEST-EXEC: btest-diff out2 +# @TEST-EXEC: btest-diff out3 + +@load base/protocols/snmp diff --git a/testing/btest/scripts/base/protocols/snmp/v3.bro b/testing/btest/scripts/base/protocols/snmp/v3.bro new file mode 100644 index 0000000000..43edbdc2df --- /dev/null +++ b/testing/btest/scripts/base/protocols/snmp/v3.bro @@ -0,0 +1,5 @@ +# @TEST-EXEC: bro -b -r $TRACES/snmp/snmpv3_get_next.pcap %INPUT $SCRIPTS/snmp-test.bro >out1 + +# @TEST-EXEC: btest-diff out1 + +@load base/protocols/snmp diff --git a/testing/scripts/snmp-test.bro b/testing/scripts/snmp-test.bro new file mode 100644 index 0000000000..399935db4c --- /dev/null +++ b/testing/scripts/snmp-test.bro @@ -0,0 +1,208 @@ + +function format_snmp_val(tag: count, s: string): string + { + return fmt(" value (tag=0x%02x): %s", tag, s); + } + +function print_snmp_value(val: SNMP::ObjectValue) + { + switch ( val$tag ) { + case SNMP::OBJ_OID_TAG: + print format_snmp_val(val$tag, fmt("%s", val$oid)); + break; + + case SNMP::OBJ_INTEGER_TAG: + print format_snmp_val(val$tag, fmt("%s", val$signed)); + break; + + case SNMP::OBJ_COUNTER32_TAG, + SNMP::OBJ_UNSIGNED32_TAG, + SNMP::OBJ_TIMETICKS_TAG, + SNMP::OBJ_COUNTER64_TAG: + print format_snmp_val(val$tag, fmt("%s", val$unsigned)); + break; + + case SNMP::OBJ_IPADDRESS_TAG: + print format_snmp_val(val$tag, fmt("%s", val$address)); + break; + + case SNMP::OBJ_OCTETSTRING_TAG, + SNMP::OBJ_OPAQUE_TAG: + print format_snmp_val(val$tag, fmt("%s", val$octets)); + break; + + case SNMP::OBJ_UNSPECIFIED_TAG: + print format_snmp_val(val$tag, fmt("%s", "")); + break; + + case SNMP::OBJ_NOSUCHOBJECT_TAG: + print format_snmp_val(val$tag, fmt("%s", "")); + break; + + case SNMP::OBJ_NOSUCHINSTANCE_TAG: + print format_snmp_val(val$tag, fmt("%s", "")); + break; + + case SNMP::OBJ_ENDOFMIBVIEW_TAG: + print format_snmp_val(val$tag, fmt("%s", "")); + break; + + default: + print format_snmp_val(val$tag, ""); + break; + } + } + +function print_snmp_binding(binding: SNMP::Binding) + { + print fmt(" oid: %s", binding$oid); + print_snmp_value(binding$value); + } + +function print_snmp_bindings(bindings: SNMP::Bindings) + { + for ( i in bindings ) + print_snmp_binding(bindings[i]); + } + +function print_snmp_pdu(pdu: SNMP::PDU) + { + print fmt(" request_id: %s", pdu$request_id); + print fmt(" error_stat: %s", pdu$error_status); + print fmt(" error_idx: %s", pdu$error_index); + print_snmp_bindings(pdu$bindings); + } + +function print_snmp_trap_pdu(pdu: SNMP::TrapPDU) + { + print fmt(" enterprise: %s", pdu$enterprise); + print fmt(" agent: %s", pdu$agent); + print fmt(" generic_trap: %s", pdu$generic_trap); + print fmt(" specific_trap: %s", pdu$specific_trap); + print fmt(" time_stamp: %s", pdu$time_stamp); + print_snmp_bindings(pdu$bindings); + } + +function print_snmp_bulk_pdu(pdu: SNMP::BulkPDU) + { + print fmt(" request_id: %s", pdu$request_id); + print fmt(" non_repeaters: %s", pdu$non_repeaters); + print fmt(" max_repititions: %s", pdu$max_repititions); + print_snmp_bindings(pdu$bindings); + } + +function print_snmp_conn(c: connection, is_orig: bool) + { + print fmt(" %s", c$id); + print fmt(" is_orig: %s", is_orig); + } + +function print_snmp_header(header: SNMP::Header) + { + switch ( header$version ) { + case 0: + print fmt(" %s", header$v1); + break; + + case 1: + print fmt(" %s", header$v2); + break; + + case 3: + print fmt(" %s", header$v3); + break; + + default: + break; + } + } + +function print_snmp(msg: string, c: connection, is_orig: bool, + header: SNMP::Header, pdu: SNMP::PDU) + { + print msg; + print_snmp_conn(c, is_orig); + print_snmp_header(header); + print_snmp_pdu(pdu); + } + +event snmp_get_request(c: connection, is_orig: bool, header: SNMP::Header, pdu: SNMP::PDU) + { + print_snmp("snmp_get_request", c, is_orig, header, pdu); + } + +event snmp_get_next_request(c: connection, is_orig: bool, header: SNMP::Header, pdu: SNMP::PDU) + { + print_snmp("snmp_get_request", c, is_orig, header, pdu); + } + +event snmp_response(c: connection, is_orig: bool, header: SNMP::Header, pdu: SNMP::PDU) + { + print_snmp("snmp_response", c, is_orig, header, pdu); + } + +event snmp_set_request(c: connection, is_orig: bool, header: SNMP::Header, pdu: SNMP::PDU) + { + print_snmp("snmp_set_request", c, is_orig, header, pdu); + } + +event snmp_trap(c: connection, is_orig: bool, header: SNMP::Header, pdu: SNMP::TrapPDU) + { + print "snmp_trap"; + print_snmp_conn(c, is_orig); + print_snmp_header(header); + print_snmp_trap_pdu(pdu); + } + +event snmp_get_bulk_request(c: connection, is_orig: bool, header: SNMP::Header, pdu: SNMP::BulkPDU) + { + print "snmp_get_bulk_request"; + print_snmp_conn(c, is_orig); + print_snmp_header(header); + print_snmp_bulk_pdu(pdu); + } + +event snmp_inform_request(c: connection, is_orig: bool, header: SNMP::Header, pdu: SNMP::PDU) + { + print_snmp("snmp_inform_request", c, is_orig, header, pdu); + } + +event snmp_trapV2(c: connection, is_orig: bool, header: SNMP::Header, pdu: SNMP::PDU) + { + print_snmp("snmp_trapv2", c, is_orig, header, pdu); + } + +event snmp_report(c: connection, is_orig: bool, header: SNMP::Header, pdu: SNMP::PDU) + { + print_snmp("snmp_report", c, is_orig, header, pdu); + } + +event snmp_unknown_pdu(c: connection, is_orig: bool, header: SNMP::Header, tag: count) + { + print "snmp_unknown_pdu"; + print_snmp_conn(c, is_orig); + print_snmp_header(header); + print fmt(" tag: %s", tag); + } + +event snmp_unknown_scoped_pdu(c: connection, is_orig: bool, header: SNMP::Header, tag: count) + { + print "snmp_unknown_scoped_pdu"; + print_snmp_conn(c, is_orig); + print_snmp_header(header); + print fmt(" tag: %s", tag); + } + +event snmp_encrypted_pdu(c: connection, is_orig: bool, header: SNMP::Header) + { + print "snmp_encrypted_pdu"; + print_snmp_conn(c, is_orig); + print_snmp_header(header); + } + +event snmp_unknown_header_version(c: connection, is_orig: bool, version: count) + { + print "snmp_unknown_header_version"; + print_snmp_conn(c, is_orig); + print fmt(" version %s", version); + } From 3f008c8f0bf4378eb5f2058224293cc48da6639f Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 18 Feb 2014 15:40:41 -0600 Subject: [PATCH 082/254] Fix compiler nitpicks from new SNMP code. --- src/analyzer/protocol/snmp/snmp-analyzer.pac | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/analyzer/protocol/snmp/snmp-analyzer.pac b/src/analyzer/protocol/snmp/snmp-analyzer.pac index 1a864df8b9..cc190e6ebe 100644 --- a/src/analyzer/protocol/snmp/snmp-analyzer.pac +++ b/src/analyzer/protocol/snmp/snmp-analyzer.pac @@ -1,3 +1,11 @@ +%extern{ +#include +#include +#include + +#include "net_util.h" +#include "util.h" +%} %header{ StringVal* asn1_oid_to_val(const ASN1Encoding* oid); @@ -81,7 +89,7 @@ StringVal* asn1_oid_to_val(const ASN1Encoding* oid) } else { - std::div_t result = div(subidentifier_values[i], 40); + std::div_t result = std::div(subidentifier_values[i], 40); snprintf(tmp, sizeof(tmp), "%d", result.quot); rval += tmp; rval += "."; From 2636d3aee74fc523dac5e0c4ec7fddba4b5d3d1b Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 18 Feb 2014 15:58:53 -0600 Subject: [PATCH 083/254] Add memory leak unit test for SNMP. --- testing/btest/core/leaks/snmp.test | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 testing/btest/core/leaks/snmp.test diff --git a/testing/btest/core/leaks/snmp.test b/testing/btest/core/leaks/snmp.test new file mode 100644 index 0000000000..c58c1f5b58 --- /dev/null +++ b/testing/btest/core/leaks/snmp.test @@ -0,0 +1,10 @@ +# Needs perftools support. +# +# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks +# +# @TEST-GROUP: leaks +# +# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -b -m -r $TRACES/snmp/snmpv1_get.pcap -r $TRACES/snmp/snmpv1_get_short.pcap -r $TRACES/snmp/snmpv1_set.pcap -r $TRACES/snmp/snmpv1_trap.pcap -r $TRACES/snmp/snmpv2_get_bulk.pcap -r $TRACES/snmp/snmpv2_get_next.pcap -r $TRACES/snmp/snmpv2_get.pcap -r $TRACES/snmp/snmpv3_get_next.pcap $SCRIPTS/snmp-test.bro %INPUT +# @TEST-EXEC: btest-bg-wait 30 + +@load base/protocols/snmp From 90026f7196d721d4141077954f9a415791c48fc0 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 19 Feb 2014 10:32:27 -0600 Subject: [PATCH 084/254] Update to libmagic version 5.17, address BIT-1136. --- CMakeLists.txt | 2 +- testing/btest/bifs/identify_data.bro | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28027d63d3..f773381ae8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,7 @@ set(LIBMAGIC_LIB_DIR ${LIBMAGIC_PREFIX}/lib) set(LIBMAGIC_LIBRARY ${LIBMAGIC_LIB_DIR}/libmagic.a) ExternalProject_Add(libmagic PREFIX ${LIBMAGIC_PREFIX} - URL ${CMAKE_CURRENT_SOURCE_DIR}/src/3rdparty/file-5.16.tar.gz + URL ${CMAKE_CURRENT_SOURCE_DIR}/src/3rdparty/file-5.17.tar.gz CONFIGURE_COMMAND ./configure --enable-static --disable-shared --prefix=${LIBMAGIC_PREFIX} --includedir=${LIBMAGIC_INCLUDE_DIR} diff --git a/testing/btest/bifs/identify_data.bro b/testing/btest/bifs/identify_data.bro index 836a5a428f..d49a144b1e 100644 --- a/testing/btest/bifs/identify_data.bro +++ b/testing/btest/bifs/identify_data.bro @@ -10,7 +10,7 @@ event bro_init() print identify_data(a, T); # PNG image - local b = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"; + local b = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00"; print identify_data(b, F); print identify_data(b, T); } From 18d89d6320db4ffd15f0250b2db8a1ec11750ac4 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Thu, 20 Feb 2014 14:37:43 -0800 Subject: [PATCH 085/254] New alert from https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 --- scripts/base/protocols/ssl/consts.bro | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/base/protocols/ssl/consts.bro b/scripts/base/protocols/ssl/consts.bro index b81aebfbbb..c50ad13648 100644 --- a/scripts/base/protocols/ssl/consts.bro +++ b/scripts/base/protocols/ssl/consts.bro @@ -55,6 +55,7 @@ export { [113] = "bad_certificate_status_response", [114] = "bad_certificate_hash_value", [115] = "unknown_psk_identity", + [120] = "no_application_protocol", } &default=function(i: count):string { return fmt("unknown-%d", i); }; ## Mapping between numeric codes and human readable strings for SSL/TLS From 10d89a464896f3d041985672c9910c3fb14bdcda Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 20 Feb 2014 17:27:46 -0800 Subject: [PATCH 086/254] Updating submodule(s). [nomail] --- CHANGES | 4 ++++ VERSION | 2 +- src/3rdparty | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index ba9102aeeb..1b4d3841bd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,8 @@ +2.2-177 | 2014-02-20 17:27:46 -0800 + + * Update to libmagic version 5.17. Addresses BIT-1136. (Jon Siwek) + 2.2-174 | 2014-02-14 12:07:04 -0800 * Support for MPLS over VLAN. (Chris Kanich) diff --git a/VERSION b/VERSION index 5b847786b5..598049d62c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2-174 +2.2-177 diff --git a/src/3rdparty b/src/3rdparty index 42a4c9694a..e96d95a130 160000 --- a/src/3rdparty +++ b/src/3rdparty @@ -1 +1 @@ -Subproject commit 42a4c9694a2b2677b050fbb7cbae26bc5ec4605a +Subproject commit e96d95a130a572b611fe70b3c3ede2b4727aaa22 From 0e7d70e21924beb04cf0109e899c2b0003b55ffd Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Fri, 21 Feb 2014 06:05:12 -0800 Subject: [PATCH 087/254] Correct return type of topk_get_top, addresses BIT-1144 --- src/probabilistic/top-k.bif | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/probabilistic/top-k.bif b/src/probabilistic/top-k.bif index 5362750467..0589608d22 100644 --- a/src/probabilistic/top-k.bif +++ b/src/probabilistic/top-k.bif @@ -49,7 +49,7 @@ function topk_add%(handle: opaque of topk, value: any%): any ## ## .. bro:see:: topk_init topk_add topk_count topk_epsilon ## topk_size topk_sum topk_merge topk_merge_prune -function topk_get_top%(handle: opaque of topk, k: count%): any +function topk_get_top%(handle: opaque of topk, k: count%): index_vec %{ assert(handle); probabilistic::TopkVal* h = (probabilistic::TopkVal*) handle; From 81e561e5dea6a00c7d70058974964434450fe292 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Fri, 21 Feb 2014 11:18:35 -0800 Subject: [PATCH 088/254] Revert "Correct return type of topk_get_top, addresses BIT-1144" This reverts commit 0e7d70e21924beb04cf0109e899c2b0003b55ffd. Sorry, bad idea. --- src/probabilistic/top-k.bif | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/probabilistic/top-k.bif b/src/probabilistic/top-k.bif index 0589608d22..5362750467 100644 --- a/src/probabilistic/top-k.bif +++ b/src/probabilistic/top-k.bif @@ -49,7 +49,7 @@ function topk_add%(handle: opaque of topk, value: any%): any ## ## .. bro:see:: topk_init topk_add topk_count topk_epsilon ## topk_size topk_sum topk_merge topk_merge_prune -function topk_get_top%(handle: opaque of topk, k: count%): index_vec +function topk_get_top%(handle: opaque of topk, k: count%): any %{ assert(handle); probabilistic::TopkVal* h = (probabilistic::TopkVal*) handle; From ca2cdd88615584e782564d334e703883f40f6abf Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Fri, 21 Feb 2014 11:24:03 -0800 Subject: [PATCH 089/254] new TLS constants from https://tools.ietf.org/html/draft-bmoeller-tls-downgrade-scsv-01 --- scripts/base/protocols/ssl/consts.bro | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/base/protocols/ssl/consts.bro b/scripts/base/protocols/ssl/consts.bro index c50ad13648..9e9222f12c 100644 --- a/scripts/base/protocols/ssl/consts.bro +++ b/scripts/base/protocols/ssl/consts.bro @@ -47,6 +47,7 @@ export { [70] = "protocol_version", [71] = "insufficient_security", [80] = "internal_error", + [86] = "inappropriate_fallback", [90] = "user_canceled", [100] = "no_renegotiation", [110] = "unsupported_extension", @@ -264,6 +265,8 @@ export { const TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C3; const TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C4; const TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C5; + # draft-bmoeller-tls-downgrade-scsv-01 + const TLS_FALLBACK_SCSV = 0x5600; # RFC 4492 const TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001; const TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002; @@ -630,6 +633,7 @@ export { [TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256] = "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", [TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256] = "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", [TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA256] = "TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA256", + [TLS_FALLBACK_SCSV] = "TLS_FALLBACK_SCSV", [TLS_ECDH_ECDSA_WITH_NULL_SHA] = "TLS_ECDH_ECDSA_WITH_NULL_SHA", [TLS_ECDH_ECDSA_WITH_RC4_128_SHA] = "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", [TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA] = "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", From 09c2491896971ef361e3ca339175e625c98d406e Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Mon, 24 Feb 2014 08:13:38 -0800 Subject: [PATCH 090/254] Remove unused and potentially unsafe function ListVal::IncludedInString --- src/Val.cc | 17 ----------------- src/Val.h | 7 ------- 2 files changed, 24 deletions(-) diff --git a/src/Val.cc b/src/Val.cc index e072914afb..8c60f4c490 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -1171,23 +1171,6 @@ ListVal::~ListVal() Unref(type); } -const char* ListVal::IncludedInString(const char* str) const - { - if ( tag != TYPE_STRING ) - Internal("non-string list in ListVal::IncludedInString"); - - loop_over_list(vals, i) - { - const char* vs = (const char*) (vals[i]->AsString()->Bytes()); - - const char* embedded = strstr(str, vs); - if ( embedded ) - return embedded; - } - - return 0; - } - RE_Matcher* ListVal::BuildRE() const { if ( tag != TYPE_STRING ) diff --git a/src/Val.h b/src/Val.h index 33bd89c0d5..3d4141cd7a 100644 --- a/src/Val.h +++ b/src/Val.h @@ -669,13 +669,6 @@ public: Val* Index(const int n) { return vals[n]; } const Val* Index(const int n) const { return vals[n]; } - // Returns offset of where str includes one of the strings in this - // ListVal (which had better be a list of strings), nil if none. - // - // Assumes that all of the strings in the list are NUL-terminated - // and do not have any embedded NULs. - const char* IncludedInString(const char* str) const; - // Returns an RE_Matcher() that will match any string that // includes embedded within it one of the patterns listed // (as a string, e.g., "foo|bar") in this ListVal. From bc75988bd9e76bc595a086d61e2ee2fa960209a0 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Mon, 24 Feb 2014 12:53:48 -0800 Subject: [PATCH 091/254] More google tls extensions that are being actively used. --- 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 9e9222f12c..1ccace102c 100644 --- a/scripts/base/protocols/ssl/consts.bro +++ b/scripts/base/protocols/ssl/consts.bro @@ -89,6 +89,8 @@ export { [13175] = "origin_bound_certificates", [13180] = "encrypted_client_certificates", [30031] = "channel_id", + [30032] = "channel_id_new", + [35655] = "padding", [65281] = "renegotiation_info" } &default=function(i: count):string { return fmt("unknown-%d", i); }; From b3bd509b3fa9d4803d7bec15399faf0471085b31 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Tue, 25 Feb 2014 15:30:29 -0800 Subject: [PATCH 092/254] Allow iterating over bif functions with result type vector of any. This changes the internal type that is used to signal that a vector is unspecified from any to void. I tried to verify that the behavior of Bro is still the same. After a lot of playing around, I think everything still should worl as before. However, it might be good for someone to take a look at this. addresses BIT-1144 --- scripts/base/init-bare.bro | 7 +++++++ src/Expr.cc | 4 +++- src/Type.cc | 17 ++++++++++++++++- src/Type.h | 2 +- src/Val.cc | 6 ++++-- src/Val.h | 2 ++ src/probabilistic/top-k.bif | 2 +- testing/btest/Baseline/bifs.topk/out | 9 +++++++++ .../Baseline/language.vector-unspecified/output | 1 + testing/btest/bifs/topk.bro | 12 +++++++++++- testing/btest/language/vector-unspecified.bro | 11 +++++++++++ 11 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 testing/btest/Baseline/language.vector-unspecified/output create mode 100644 testing/btest/language/vector-unspecified.bro diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index d4e631ecf4..80747e5564 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -39,6 +39,13 @@ type count_set: set[count]; ## directly and then remove this alias. type index_vec: vector of count; +## A vector of any, used by some builtin functions to store a list of varying types. +## +## .. todo:: We need this type definition only for declaring builtin functions +## via ``bifcl``. We should extend ``bifcl`` to understand composite types +## directly and then remove this alias. +type any_vec: vector of any; + ## A vector of strings. ## ## .. todo:: We need this type definition only for declaring builtin functions diff --git a/src/Expr.cc b/src/Expr.cc index 5f6c7d41c6..a5315b533d 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -3819,7 +3819,9 @@ VectorConstructorExpr::VectorConstructorExpr(ListExpr* constructor_list, if ( constructor_list->Exprs().length() == 0 ) { // vector(). - SetType(new ::VectorType(base_type(TYPE_ANY))); + // By default, assign VOID type here. A vector with + // void type set is seen as an unspecified vector. + SetType(new ::VectorType(base_type(TYPE_VOID))); return; } diff --git a/src/Type.cc b/src/Type.cc index 340ab973bc..61adbbad87 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -1626,6 +1626,21 @@ VectorType::~VectorType() Unref(yield_type); } +BroType* VectorType::YieldType() + { + // cheat around the fact that we use void internally to + // mark a vector as being unspecified + if ( IsUnspecifiedVector() ) + { + BroType* ret = ::base_type(TYPE_ANY); + Unref(ret); // unref, because this won't be held by anyone. + assert(ret); + return ret; + } + + return yield_type; + } + int VectorType::MatchesIndex(ListExpr*& index) const { expr_list& el = index->Exprs(); @@ -1645,7 +1660,7 @@ int VectorType::MatchesIndex(ListExpr*& index) const bool VectorType::IsUnspecifiedVector() const { - return yield_type->Tag() == TYPE_ANY; + return yield_type->Tag() == TYPE_VOID; } IMPLEMENT_SERIAL(VectorType, SER_VECTOR_TYPE); diff --git a/src/Type.h b/src/Type.h index f6328aed4a..361c2794f0 100644 --- a/src/Type.h +++ b/src/Type.h @@ -572,7 +572,7 @@ class VectorType : public BroType { public: VectorType(BroType* t); virtual ~VectorType(); - BroType* YieldType() { return yield_type; } + BroType* YieldType(); int MatchesIndex(ListExpr*& index) const; diff --git a/src/Val.cc b/src/Val.cc index e072914afb..46a2f89cca 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -2976,7 +2976,9 @@ VectorVal::~VectorVal() bool VectorVal::Assign(unsigned int index, Val* element, Opcode op) { if ( element && - ! same_type(element->Type(), vector_type->YieldType(), 0) ) + ! same_type(element->Type(), vector_type->YieldType(), 0) && + // if we are unspecified, you can assign anything to us. + ! vector_type->IsUnspecifiedVector() ) { Unref(element); return false; @@ -3139,7 +3141,7 @@ bool VectorVal::DoUnserialize(UnserialInfo* info) for ( int i = 0; i < len; ++i ) { Val* v; - UNSERIALIZE_OPTIONAL(v, Val::Unserialize(info, TYPE_ANY)); + UNSERIALIZE_OPTIONAL(v, Val::Unserialize(info, TYPE_ANY)); // accept any type Assign(i, v); } diff --git a/src/Val.h b/src/Val.h index 33bd89c0d5..f44bba2059 100644 --- a/src/Val.h +++ b/src/Val.h @@ -656,6 +656,8 @@ protected: DECLARE_SERIAL(PatternVal); }; +// ListVals are mainly used to index tables that have more than one +// element in their index. class ListVal : public Val { public: ListVal(TypeTag t); diff --git a/src/probabilistic/top-k.bif b/src/probabilistic/top-k.bif index 5362750467..8f7b071a4c 100644 --- a/src/probabilistic/top-k.bif +++ b/src/probabilistic/top-k.bif @@ -49,7 +49,7 @@ function topk_add%(handle: opaque of topk, value: any%): any ## ## .. bro:see:: topk_init topk_add topk_count topk_epsilon ## topk_size topk_sum topk_merge topk_merge_prune -function topk_get_top%(handle: opaque of topk, k: count%): any +function topk_get_top%(handle: opaque of topk, k: count%): any_vec %{ assert(handle); probabilistic::TopkVal* h = (probabilistic::TopkVal*) handle; diff --git a/testing/btest/Baseline/bifs.topk/out b/testing/btest/Baseline/bifs.topk/out index 1ce5c4b850..48d7e23f96 100644 --- a/testing/btest/Baseline/bifs.topk/out +++ b/testing/btest/Baseline/bifs.topk/out @@ -79,3 +79,12 @@ 0 8 0 +0, c +1, e +2, d +0, c +1, e +2, d +0, c +1, e +2, d diff --git a/testing/btest/Baseline/language.vector-unspecified/output b/testing/btest/Baseline/language.vector-unspecified/output new file mode 100644 index 0000000000..8d726561ab --- /dev/null +++ b/testing/btest/Baseline/language.vector-unspecified/output @@ -0,0 +1 @@ +[5, Hi, 127.0.0.1] diff --git a/testing/btest/bifs/topk.bro b/testing/btest/bifs/topk.bro index 02d13c4195..1e650335a7 100644 --- a/testing/btest/bifs/topk.bro +++ b/testing/btest/bifs/topk.bro @@ -148,7 +148,17 @@ event bro_init() print topk_count(k3, "d"); print topk_epsilon(k3, "d"); - + local styped: vector of count; + styped = topk_get_top(k3, 3); + for ( i in styped ) + print i, styped[i]; + local anytyped: vector of any; + anytyped = topk_get_top(k3, 3); + for ( i in anytyped ) + print i, anytyped[i]; + local suntyped = topk_get_top(k3, 3); + for ( i in suntyped ) + print i, suntyped[i]; } diff --git a/testing/btest/language/vector-unspecified.bro b/testing/btest/language/vector-unspecified.bro new file mode 100644 index 0000000000..b91f910504 --- /dev/null +++ b/testing/btest/language/vector-unspecified.bro @@ -0,0 +1,11 @@ +# @TEST-EXEC: bro -b %INPUT >output 2>&1 +# @TEST-EXEC: btest-diff output + +# Test assignment behavior of unspecified vectors +local a = vector(); + +a[0] = 5; +a[1] = "Hi"; +a[2] = 127.0.0.1; + +print a; From 3f584a08fddb16e4da24eec852a6eb843c6f971e Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Tue, 25 Feb 2014 19:20:42 -0800 Subject: [PATCH 093/254] Remove packet sorter. Addresses BIT-700 --- scripts/base/init-bare.bro | 7 - src/CMakeLists.txt | 1 - src/Net.cc | 77 +------ src/Net.h | 2 +- src/NetVar.cc | 4 - src/NetVar.h | 2 - src/PacketSort.cc | 364 -------------------------------- src/PacketSort.h | 132 ------------ src/PktSrc.cc | 10 +- src/RemoteSerializer.cc | 2 +- src/Sessions.cc | 102 ++++----- src/Sessions.h | 6 +- src/analyzer/protocol/arp/ARP.h | 6 +- 13 files changed, 65 insertions(+), 650 deletions(-) delete mode 100644 src/PacketSort.cc delete mode 100644 src/PacketSort.h diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index d4e631ecf4..46a838e8ae 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -1028,13 +1028,6 @@ const rpc_timeout = 24 sec &redef; ## means "forever", which resists evasion, but can lead to state accrual. const frag_timeout = 0.0 sec &redef; -## Time window for reordering packets. This is used for dealing with timestamp -## discrepancy between multiple packet sources. -## -## .. note:: Setting this can have a major performance impact as now packets -## need to be potentially copied and buffered. -const packet_sort_window = 0 usecs &redef; - ## If positive, indicates the encapsulation header size that should ## be skipped. This applies to all packets. const encap_hdr_size = 0 &redef; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c85b3b526f..ecf8683ddd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -293,7 +293,6 @@ set(bro_SRCS OpaqueVal.cc OSFinger.cc PacketFilter.cc - PacketSort.cc PersistenceSerializer.cc PktSrc.cc PolicyFile.cc diff --git a/src/Net.cc b/src/Net.cc index ac4dacf9b8..83fcde1df4 100644 --- a/src/Net.cc +++ b/src/Net.cc @@ -27,7 +27,6 @@ #include "Reporter.h" #include "Net.h" #include "Anon.h" -#include "PacketSort.h" #include "Serializer.h" #include "PacketDumper.h" @@ -58,8 +57,6 @@ double bro_start_network_time; // timestamp of first packet double last_watchdog_proc_time = 0.0; // value of above during last watchdog bool terminating = false; // whether we're done reading and finishing up -PacketSortGlobalPQ* packet_sorter = 0; - const struct pcap_pkthdr* current_hdr = 0; const u_char* current_pkt = 0; int current_dispatched = 0; @@ -286,9 +283,6 @@ void net_init(name_list& interfaces, name_list& readfiles, init_ip_addr_anonymizers(); - if ( packet_sort_window > 0 ) - packet_sorter = new PacketSortGlobalPQ(); - sessions = new NetSessions(); if ( do_watchdog ) @@ -313,7 +307,7 @@ void expire_timers(PktSrc* src_ps) void net_packet_dispatch(double t, const struct pcap_pkthdr* hdr, const u_char* pkt, int hdr_size, - PktSrc* src_ps, PacketSortElement* pkt_elem) + PktSrc* src_ps) { if ( ! bro_start_network_time ) bro_start_network_time = t; @@ -351,7 +345,7 @@ void net_packet_dispatch(double t, const struct pcap_pkthdr* hdr, } } - sessions->DispatchPacket(t, hdr, pkt, hdr_size, src_ps, pkt_elem); + sessions->DispatchPacket(t, hdr, pkt, hdr_size, src_ps); mgr.Drain(); if ( sp ) @@ -367,62 +361,11 @@ void net_packet_dispatch(double t, const struct pcap_pkthdr* hdr, current_pktsrc = 0; } -int process_packet_sorter(double latest_packet_time) - { - if ( ! packet_sorter ) - return 0; - - double min_t = latest_packet_time - packet_sort_window; - - int num_pkts_dispatched = 0; - PacketSortElement* pkt_elem; - - // Dispatch packets in the packet_sorter until timestamp min_t. - // It's possible that zero or multiple packets are dispatched. - while ( (pkt_elem = packet_sorter->RemoveMin(min_t)) != 0 ) - { - net_packet_dispatch(pkt_elem->TimeStamp(), - pkt_elem->Hdr(), pkt_elem->Pkt(), - pkt_elem->HdrSize(), pkt_elem->Src(), - pkt_elem); - ++num_pkts_dispatched; - delete pkt_elem; - } - - return num_pkts_dispatched; - } - -void net_packet_arrival(double t, const struct pcap_pkthdr* hdr, - const u_char* pkt, int hdr_size, - PktSrc* src_ps) - { - if ( packet_sorter ) - { - // Note that when we enable packet sorter, there will - // be a small window between the time packet arrives - // to Bro and when it is processed ("dispatched"). We - // define network_time to be the latest timestamp for - // packets *dispatched* so far (usually that's the - // timestamp of the current packet). - - // Add the packet to the packet_sorter. - packet_sorter->Add( - new PacketSortElement(src_ps, t, hdr, pkt, hdr_size)); - - // Do we have any packets to dispatch from packet_sorter? - process_packet_sorter(t); - } - else - // Otherwise we dispatch the packet immediately - net_packet_dispatch(t, hdr, pkt, hdr_size, src_ps, 0); - } - void net_run() { set_processing_status("RUNNING", "net_run"); while ( io_sources.Size() || - (packet_sorter && ! packet_sorter->Empty()) || (BifConst::exit_only_after_terminate && ! terminating) ) { double ts; @@ -445,14 +388,12 @@ void net_run() current_iosrc = src; if ( src ) - src->Process(); // which will call net_packet_arrival() + src->Process(); // which will call net_packet_dispatch() else if ( reading_live && ! pseudo_realtime) { // live but no source is currently active double ct = current_time(); - if ( packet_sorter && ! packet_sorter->Empty() ) - process_packet_sorter(ct); - else if ( ! net_is_processing_suspended() ) + if ( ! net_is_processing_suspended() ) { // Take advantage of the lull to get up to // date on timers and events. @@ -462,15 +403,6 @@ void net_run() } } - else if ( packet_sorter && ! packet_sorter->Empty() ) - { - // We are no longer reading live; done with all the - // sources. - // Drain packets remaining in the packet sorter. - process_packet_sorter( - network_time + packet_sort_window + 1000000); - } - else if ( (have_pending_timers || using_communication) && ! pseudo_realtime ) { @@ -581,7 +513,6 @@ void net_delete() set_processing_status("TERMINATING", "net_delete"); delete sessions; - delete packet_sorter; for ( int i = 0; i < NUM_ADDR_ANONYMIZATION_METHODS; ++i ) delete ip_anonymizer[i]; diff --git a/src/Net.h b/src/Net.h index 07c856d1dd..b5b25b0cee 100644 --- a/src/Net.h +++ b/src/Net.h @@ -20,7 +20,7 @@ extern void net_run(); extern void net_get_final_stats(); extern void net_finish(int drain_events); extern void net_delete(); // Reclaim all memory, etc. -extern void net_packet_arrival(double t, const struct pcap_pkthdr* hdr, +extern void net_packet_dispatch(double t, const struct pcap_pkthdr* hdr, const u_char* pkt, int hdr_size, PktSrc* src_ps); extern int net_packet_match(BPF_Program* fp, const u_char* pkt, diff --git a/src/NetVar.cc b/src/NetVar.cc index 05a4e16b47..3e13728cd8 100644 --- a/src/NetVar.cc +++ b/src/NetVar.cc @@ -156,8 +156,6 @@ int table_incremental_step; RecordType* packet_type; -double packet_sort_window; - double connection_status_update_interval; StringVal* state_dir; @@ -481,8 +479,6 @@ void init_net_var() packet_type = internal_type("packet")->AsRecordType(); - packet_sort_window = opt_internal_double("packet_sort_window"); - orig_addr_anonymization = opt_internal_int("orig_addr_anonymization"); resp_addr_anonymization = opt_internal_int("resp_addr_anonymization"); other_addr_anonymization = opt_internal_int("other_addr_anonymization"); diff --git a/src/NetVar.h b/src/NetVar.h index 8ef6571313..6a56e957ae 100644 --- a/src/NetVar.h +++ b/src/NetVar.h @@ -159,8 +159,6 @@ extern int table_incremental_step; extern RecordType* packet_type; -extern double packet_sort_window; - extern int orig_addr_anonymization, resp_addr_anonymization; extern int other_addr_anonymization; extern TableVal* preserve_orig_addr; diff --git a/src/PacketSort.cc b/src/PacketSort.cc deleted file mode 100644 index 429d8e2720..0000000000 --- a/src/PacketSort.cc +++ /dev/null @@ -1,364 +0,0 @@ -#include "IP.h" -#include "PacketSort.h" - -const bool DEBUG_packetsort = false; - -PacketSortElement::PacketSortElement(PktSrc* arg_src, - double arg_timestamp, const struct pcap_pkthdr* arg_hdr, - const u_char* arg_pkt, int arg_hdr_size) - { - src = arg_src; - timestamp = arg_timestamp; - hdr = *arg_hdr; - hdr_size = arg_hdr_size; - - pkt = new u_char[hdr.caplen]; - memcpy(pkt, arg_pkt, hdr.caplen); - - is_tcp = 0; - ip_hdr = 0; - tcp_flags = 0; - endp = 0; - payload_length = 0; - key = 0; - - // Now check if it is a "parsable" TCP packet. - uint32 caplen = hdr.caplen; - uint32 tcp_offset; - - if ( caplen >= sizeof(struct ip) + hdr_size ) - { - const struct ip* ip = (const struct ip*) (pkt + hdr_size); - if ( ip->ip_v == 4 ) - ip_hdr = new IP_Hdr(ip, false); - else if ( ip->ip_v == 6 && (caplen >= sizeof(struct ip6_hdr) + hdr_size) ) - ip_hdr = new IP_Hdr((const struct ip6_hdr*) ip, false, caplen - hdr_size); - else - // Weird will be generated later in NetSessions::NextPacket. - return; - - if ( ip_hdr->NextProto() == IPPROTO_TCP && - // Note: can't sort fragmented packets - ( ! ip_hdr->IsFragment() ) ) - { - tcp_offset = hdr_size + ip_hdr->HdrLen(); - if ( caplen >= tcp_offset + sizeof(struct tcphdr) ) - { - const struct tcphdr* tp = (const struct tcphdr*) - (pkt + tcp_offset); - - id.src_addr = ip_hdr->SrcAddr(); - id.dst_addr = ip_hdr->DstAddr(); - id.src_port = tp->th_sport; - id.dst_port = tp->th_dport; - id.is_one_way = 0; - - endp = addr_port_canon_lt(id.src_addr, - id.src_port, - id.dst_addr, - id.dst_port) ? 0 : 1; - - seq[endp] = ntohl(tp->th_seq); - - if ( tp->th_flags & TH_ACK ) - seq[1-endp] = ntohl(tp->th_ack); - else - seq[1-endp] = 0; - - tcp_flags = tp->th_flags; - - // DEBUG_MSG("%.6f: %u, %u\n", timestamp, seq[0], seq[1]); - - payload_length = ip_hdr->PayloadLen() - tp->th_off * 4; - - key = BuildConnIDHashKey(id); - - is_tcp = 1; - } - } - } - - if ( DEBUG_packetsort && ! is_tcp ) - DEBUG_MSG("%.6f non-TCP packet\n", timestamp); - } - -PacketSortElement::~PacketSortElement() - { - delete [] pkt; - delete ip_hdr; - delete key; - } - -int PacketSortPQ::Timestamp_Cmp(PacketSortElement* a, PacketSortElement* b) - { - double d = a->timestamp - b->timestamp; - - if ( d > 0 ) return 1; - else if ( d < 0 ) return -1; - else return 0; - } - -int PacketSortPQ::UpdatePQ(PacketSortElement* prev_e, PacketSortElement* new_e) - { - int index = prev_e->pq_index[pq_level]; - - new_e->pq_index[pq_level] = index; - pq[index] = new_e; - - if ( Cmp(prev_e, new_e) > 0 ) - return FixUp(new_e, index); - else - { - FixDown(new_e, index); - return index == 0; - } - } - -int PacketSortPQ::AddToPQ(PacketSortElement* new_e) - { - int index = pq.size(); - - new_e->pq_index[pq_level] = index; - pq.push_back(new_e); - - return FixUp(new_e, index); - } - -int PacketSortPQ::RemoveFromPQ(PacketSortElement* prev_e) - { - if ( pq.size() > 1 ) - { - PacketSortElement* new_e = pq[pq.size() - 1]; - pq.pop_back(); - return UpdatePQ(prev_e, new_e); - } - else - { - pq.pop_back(); - return 1; - } - } - -void PacketSortPQ::Assign(int k, PacketSortElement* e) - { - pq[k] = e; - e->pq_index[pq_level] = k; - } - -PacketSortConnPQ::~PacketSortConnPQ() - { - // Delete elements only in ConnPQ (not in GlobalPQ) to avoid - // double delete. - for ( int i = 0; i < (int) pq.size(); ++i ) - { - delete pq[i]; - pq[i] = 0; - } - } - -int PacketSortConnPQ::Cmp(PacketSortElement* a, PacketSortElement* b) - { - // Note: here we do not distinguish between packets without - // an ACK and packets with seq/ack of 0. The later will sorted - // only by their timestamps. - - if ( a->seq[0] && b->seq[0] && a->seq[0] != b->seq[0] ) - return (a->seq[0] > b->seq[0]) ? 1 : -1; - - else if ( a->seq[1] && b->seq[1] && a->seq[1] != b->seq[1] ) - return (a->seq[1] > b->seq[1]) ? 1 : -1; - - else - return Timestamp_Cmp(a, b); - } - -int PacketSortPQ::FixUp(PacketSortElement* e, int k) - { - if ( k == 0 ) - { - Assign(0, e); - return 1; - } - - int parent = (k-1) / 2; - if ( Cmp(pq[parent], e) > 0 ) - { - Assign(k, pq[parent]); - return FixUp(e, parent); - } - else - { - Assign(k, e); - return 0; - } - } - -void PacketSortPQ::FixDown(PacketSortElement* e, int k) - { - uint32 kid = k * 2 + 1; - - if ( kid >= pq.size() ) - { - Assign(k, e); - return; - } - - if ( kid + 1 < pq.size() && Cmp(pq[kid], pq[kid+1]) > 0 ) - ++kid; - - if ( Cmp(e, pq[kid]) > 0 ) - { - Assign(k, pq[kid]); - FixDown(e, kid); - } - else - Assign(k, e); - } - - -int PacketSortConnPQ::Add(PacketSortElement* e) - { -#if 0 - int endp = e->endp; - uint32 end_seq = e->seq[endp] + e->payload_length; - - int p = 1 - endp; - if ( (e->tcp_flags & TH_RST) && ! (e->tcp_flags & TH_ACK) ) - { - DEBUG_MSG("%.6f %c: %u -> %u\n", - e->TimeStamp(), (p == endp) ? 'S' : 'A', - e->seq[p], next_seq[p]); - e->seq[p] = next_seq[p]; - } - - if ( end_seq > next_seq[endp] ) - next_seq[endp] = end_seq; -#endif - - return AddToPQ(e); - } - -void PacketSortConnPQ::UpdateDeliveredSeq(int endp, int seq, int len, int ack) - { - if ( delivered_seq[endp] == 0 || delivered_seq[endp] == seq ) - delivered_seq[endp] = seq + len; - if ( ack > delivered_seq[1 - endp] ) - delivered_seq[endp] = ack; - } - -bool PacketSortConnPQ::IsContentGapSafe(PacketSortElement* e) - { - int ack = e->seq[1 - e->endp]; - return ack <= delivered_seq[1 - e->endp]; - } - -int PacketSortConnPQ::Remove(PacketSortElement* e) - { - int ret = RemoveFromPQ(e); - UpdateDeliveredSeq(e->endp, e->seq[e->endp], e->payload_length, - e->seq[1 - e->endp]); - return ret; - } - -static void DeleteConnPQ(void* p) - { - delete (PacketSortConnPQ*) p; - } - -PacketSortGlobalPQ::PacketSortGlobalPQ() - { - pq_level = GLOBAL_PQ; - conn_pq_table.SetDeleteFunc(DeleteConnPQ); - } - -PacketSortGlobalPQ::~PacketSortGlobalPQ() - { - // Destruction of PacketSortConnPQ will delete all conn_pq's. - } - -int PacketSortGlobalPQ::Add(PacketSortElement* e) - { - if ( e->is_tcp ) - { - // TCP packets are sorted by sequence numbers - PacketSortConnPQ* conn_pq = FindConnPQ(e); - PacketSortElement* prev_min = conn_pq->Min(); - - if ( conn_pq->Add(e) ) - { - ASSERT(conn_pq->Min() != prev_min); - - if ( prev_min ) - return UpdatePQ(prev_min, e); - else - return AddToPQ(e); - } - - else - { - ASSERT(conn_pq->Min() == prev_min); - return 0; - } - } - else - return AddToPQ(e); - } - -PacketSortElement* PacketSortGlobalPQ::RemoveMin(double timestamp) - { - PacketSortElement* e = Min(); - - if ( ! e ) - return 0; - - if ( e->is_tcp ) - { - PacketSortConnPQ* conn_pq = FindConnPQ(e); - -#if 0 - // Note: the content gap safety check does not work - // because we remove the state for a connection once - // it has no packet in the priority queue. - - // Do not deliver e if it arrives later than timestamp, - // and is not content-gap-safe. - if ( e->timestamp > timestamp && - ! conn_pq->IsContentGapSafe(e) ) - return 0; -#else - if ( e->timestamp > timestamp ) - return 0; -#endif - - conn_pq->Remove(e); - PacketSortElement* new_e = conn_pq->Min(); - - if ( new_e ) - UpdatePQ(e, new_e); - else - { - RemoveFromPQ(e); - conn_pq_table.Remove(e->key); - delete conn_pq; - } - } - else - RemoveFromPQ(e); - - return e; - } - -PacketSortConnPQ* PacketSortGlobalPQ::FindConnPQ(PacketSortElement* e) - { - if ( ! e->is_tcp ) - reporter->InternalError("cannot find a connection for an invalid id"); - - PacketSortConnPQ* pq = (PacketSortConnPQ*) conn_pq_table.Lookup(e->key); - if ( ! pq ) - { - pq = new PacketSortConnPQ(); - conn_pq_table.Insert(e->key, pq); - } - - return pq; - } diff --git a/src/PacketSort.h b/src/PacketSort.h deleted file mode 100644 index 199da0732f..0000000000 --- a/src/PacketSort.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef packetsort_h -#define packetsort_h - -// Timestamps can be imprecise and even inconsistent among packets -// from different sources. This class tries to guess a "correct" -// order by looking at TCP sequence numbers. -// -// In particular, it tries to eliminate "false" content gaps. - -#include "Dict.h" -#include "Conn.h" - -enum { - CONN_PQ, - GLOBAL_PQ, - NUM_OF_PQ_LEVEL, -}; - -class PktSrc; - -class PacketSortElement { -public: - PacketSortElement(PktSrc* src, double timestamp, - const struct pcap_pkthdr* hdr, - const u_char* pkt, int hdr_size); - ~PacketSortElement(); - - PktSrc* Src() const { return src; } - double TimeStamp() const { return timestamp; } - const struct pcap_pkthdr* Hdr() const { return &hdr; } - const u_char* Pkt() const { return pkt; } - int HdrSize() const { return hdr_size; } - const IP_Hdr* IPHdr() const { return ip_hdr; } - -protected: - PktSrc* src; - double timestamp; - struct pcap_pkthdr hdr; - u_char* pkt; - int hdr_size; - - IP_Hdr* ip_hdr; - int is_tcp; - ConnID id; - uint32 seq[2]; // indexed by endpoint - int tcp_flags; - int endp; // 0 or 1 - int payload_length; - - HashKey* key; - - int pq_index[NUM_OF_PQ_LEVEL]; - - friend class PacketSortPQ; - friend class PacketSortConnPQ; - friend class PacketSortGlobalPQ; -}; - -class PacketSortPQ { -public: - PacketSortPQ() - { pq_level = -1; } - virtual ~PacketSortPQ() {} - - PacketSortElement* Min() const { return (pq.size() > 0) ? pq[0] : 0; } - -protected: - virtual int Cmp(PacketSortElement* a, PacketSortElement* b) = 0; - int Timestamp_Cmp(PacketSortElement* a, PacketSortElement* b); - - int UpdatePQ(PacketSortElement* prev_e, PacketSortElement* new_e); - int AddToPQ(PacketSortElement* e); - int RemoveFromPQ(PacketSortElement* e); - - void Assign(int k, PacketSortElement* e); - int FixUp(PacketSortElement* e, int k); - void FixDown(PacketSortElement* e, int k); - - vector pq; - int pq_level; -}; - -// Sort by sequence numbers within a connection -class PacketSortConnPQ : public PacketSortPQ { -public: - PacketSortConnPQ() - { - pq_level = CONN_PQ; - delivered_seq[0] = delivered_seq[1] = 0; - } - ~PacketSortConnPQ(); - - int Add(PacketSortElement* e); - - int Remove(PacketSortElement* e); - - bool IsContentGapSafe(PacketSortElement* e); - -protected: - int Cmp(PacketSortElement* a, PacketSortElement* b); - void UpdateDeliveredSeq(int endp, int seq, int len, int ack); - - int delivered_seq[2]; -}; - -declare(PDict, PacketSortConnPQ); - -// Sort by timestamps. -class PacketSortGlobalPQ : public PacketSortPQ { -public: - PacketSortGlobalPQ(); - ~PacketSortGlobalPQ(); - - int Add(PacketSortElement* e); - - int Empty() const { return conn_pq_table.Length() == 0; } - - // Returns the next packet to dispatch if it arrives earlier than the - // given timestamp, otherwise returns 0. - // The packet, if to be returned, is also removed from the - // priority queue. - PacketSortElement* RemoveMin(double timestamp); - -protected: - int Cmp(PacketSortElement* a, PacketSortElement* b) - { return Timestamp_Cmp(a, b); } - PacketSortConnPQ* FindConnPQ(PacketSortElement* e); - - PDict(PacketSortConnPQ) conn_pq_table; -}; - -#endif diff --git a/src/PktSrc.cc b/src/PktSrc.cc index 179630cdbd..528f10f92c 100644 --- a/src/PktSrc.cc +++ b/src/PktSrc.cc @@ -220,6 +220,12 @@ void PktSrc::Process() break; } + case DLT_IEEE802_11: + { + printf("Here\n"); + exit(0); + } + case DLT_EN10MB: { // Get protocol being carried from the ethernet frame. @@ -317,13 +323,13 @@ void PktSrc::Process() if ( pseudo_realtime ) { current_pseudo = CheckPseudoTime(); - net_packet_arrival(current_pseudo, &hdr, data, pkt_hdr_size, this); + net_packet_dispatch(current_pseudo, &hdr, data, pkt_hdr_size, this); if ( ! first_wallclock ) first_wallclock = current_time(true); } else - net_packet_arrival(current_timestamp, &hdr, data, pkt_hdr_size, this); + net_packet_dispatch(current_timestamp, &hdr, data, pkt_hdr_size, this); data = 0; } diff --git a/src/RemoteSerializer.cc b/src/RemoteSerializer.cc index c8cf03667b..8d07f34d38 100644 --- a/src/RemoteSerializer.cc +++ b/src/RemoteSerializer.cc @@ -1466,7 +1466,7 @@ void RemoteSerializer::Process() current_pkt = p->pkt; current_pktsrc = 0; current_iosrc = this; - sessions->NextPacket(p->time, p->hdr, p->pkt, p->hdr_size, 0); + sessions->NextPacket(p->time, p->hdr, p->pkt, p->hdr_size); mgr.Drain(); current_hdr = 0; // done with these diff --git a/src/Sessions.cc b/src/Sessions.cc index f7f2f37470..ec275a1689 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -30,7 +30,6 @@ #include "Discard.h" #include "RuleMatcher.h" -#include "PacketSort.h" #include "TunnelEncapsulation.h" #include "analyzer/Manager.h" @@ -168,7 +167,7 @@ void NetSessions::Done() void NetSessions::DispatchPacket(double t, const struct pcap_pkthdr* hdr, const u_char* pkt, int hdr_size, - PktSrc* src_ps, PacketSortElement* pkt_elem) + PktSrc* src_ps) { const struct ip* ip_hdr = 0; const u_char* ip_data = 0; @@ -186,14 +185,13 @@ void NetSessions::DispatchPacket(double t, const struct pcap_pkthdr* hdr, hdr_size += encap_hdr_size; if ( src_ps->FilterType() == TYPE_FILTER_NORMAL ) - NextPacket(t, hdr, pkt, hdr_size, pkt_elem); + NextPacket(t, hdr, pkt, hdr_size); else NextPacketSecondary(t, hdr, pkt, hdr_size, src_ps); } void NetSessions::NextPacket(double t, const struct pcap_pkthdr* hdr, - const u_char* const pkt, int hdr_size, - PacketSortElement* pkt_elem) + const u_char* const pkt, int hdr_size) { SegmentProfiler(segment_logger, "processing-packet"); if ( pkt_profiler ) @@ -206,70 +204,58 @@ void NetSessions::NextPacket(double t, const struct pcap_pkthdr* hdr, if ( record_all_packets ) DumpPacket(hdr, pkt); - if ( pkt_elem && pkt_elem->IPHdr() ) - // Fast path for "normal" IP packets if an IP_Hdr is - // already extracted when doing PacketSort. Otherwise - // the code below tries to extract the IP header, the - // difference here is that header extraction in - // PacketSort does not generate Weird events. + // ### The following isn't really correct. What we *should* + // do is understanding the different link layers in order to + // find the network-layer protocol ID. That's a big + // portability pain, though, unless we just assume everything's + // Ethernet .... not great, given the potential need to deal + // with PPP or FDDI (for some older traces). So instead + // we look to see if what we have is consistent with an + // IPv4 packet. If not, it's either ARP or IPv6 or weird. - DoNextPacket(t, hdr, pkt_elem->IPHdr(), pkt, hdr_size, 0); - - else + if ( hdr_size > static_cast(hdr->caplen) ) { - // ### The following isn't really correct. What we *should* - // do is understanding the different link layers in order to - // find the network-layer protocol ID. That's a big - // portability pain, though, unless we just assume everything's - // Ethernet .... not great, given the potential need to deal - // with PPP or FDDI (for some older traces). So instead - // we look to see if what we have is consistent with an - // IPv4 packet. If not, it's either ARP or IPv6 or weird. + Weird("truncated_link_frame", hdr, pkt); + return; + } - if ( hdr_size > static_cast(hdr->caplen) ) - { - Weird("truncated_link_frame", hdr, pkt); - return; - } + uint32 caplen = hdr->caplen - hdr_size; + if ( caplen < sizeof(struct ip) ) + { + Weird("truncated_IP", hdr, pkt); + return; + } - uint32 caplen = hdr->caplen - hdr_size; - if ( caplen < sizeof(struct ip) ) + const struct ip* ip = (const struct ip*) (pkt + hdr_size); + + if ( ip->ip_v == 4 ) + { + IP_Hdr ip_hdr(ip, false); + DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size, 0); + } + + else if ( ip->ip_v == 6 ) + { + if ( caplen < sizeof(struct ip6_hdr) ) { Weird("truncated_IP", hdr, pkt); return; } - const struct ip* ip = (const struct ip*) (pkt + hdr_size); + IP_Hdr ip_hdr((const struct ip6_hdr*) (pkt + hdr_size), false, caplen); + DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size, 0); + } - if ( ip->ip_v == 4 ) - { - IP_Hdr ip_hdr(ip, false); - DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size, 0); - } + else if ( analyzer::arp::ARP_Analyzer::IsARP(pkt, hdr_size) ) + { + if ( arp_analyzer ) + arp_analyzer->NextPacket(t, hdr, pkt, hdr_size); + } - else if ( ip->ip_v == 6 ) - { - if ( caplen < sizeof(struct ip6_hdr) ) - { - Weird("truncated_IP", hdr, pkt); - return; - } - - IP_Hdr ip_hdr((const struct ip6_hdr*) (pkt + hdr_size), false, caplen); - DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size, 0); - } - - else if ( analyzer::arp::ARP_Analyzer::IsARP(pkt, hdr_size) ) - { - if ( arp_analyzer ) - arp_analyzer->NextPacket(t, hdr, pkt, hdr_size); - } - - else - { - Weird("unknown_packet_type", hdr, pkt); - return; - } + else + { + Weird("unknown_packet_type", hdr, pkt); + return; } if ( dump_this_packet && ! record_all_packets ) diff --git a/src/Sessions.h b/src/Sessions.h index e2dec3b1aa..06cdbca978 100644 --- a/src/Sessions.h +++ b/src/Sessions.h @@ -28,7 +28,6 @@ declare(PDict,FragReassembler); class Discarder; class PacketFilter; -class PacketSortElement; namespace analyzer { namespace stepping_stone { class SteppingStoneManager; } } namespace analyzer { namespace arp { class ARP_Analyzer; } } @@ -74,7 +73,7 @@ public: // employing the packet sorter first. void DispatchPacket(double t, const struct pcap_pkthdr* hdr, const u_char* const pkt, int hdr_size, - PktSrc* src_ps, PacketSortElement* pkt_elem); + PktSrc* src_ps); void Done(); // call to drain events before destructing @@ -220,8 +219,7 @@ protected: uint8 tcp_flags, bool& flip_roles); void NextPacket(double t, const struct pcap_pkthdr* hdr, - const u_char* const pkt, int hdr_size, - PacketSortElement* pkt_elem); + const u_char* const pkt, int hdr_size); void NextPacketSecondary(double t, const struct pcap_pkthdr* hdr, const u_char* const pkt, int hdr_size, diff --git a/src/analyzer/protocol/arp/ARP.h b/src/analyzer/protocol/arp/ARP.h index f09dc6c398..83f447817e 100644 --- a/src/analyzer/protocol/arp/ARP.h +++ b/src/analyzer/protocol/arp/ARP.h @@ -24,7 +24,11 @@ #endif #include "NetVar.h" -#include "PacketSort.h" + +// for pcap_pkthdr +extern "C" { +#include +} namespace analyzer { namespace arp { From 80c319b522dcad8f1ee41de52d9f962fb3e615d5 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Wed, 26 Feb 2014 14:47:40 -0800 Subject: [PATCH 094/254] adjust timings of a few leak tests. Without the longer timeouts, these consistently fail for me on caddy when doing "make test". --- testing/btest/core/leaks/ayiya.test | 2 +- testing/btest/core/leaks/bloomfilter.bro | 2 +- testing/btest/core/leaks/gridftp.test | 2 +- testing/btest/core/leaks/gtp_opt_header.test | 2 +- testing/btest/core/leaks/input-reread.bro | 8 ++++---- testing/btest/core/leaks/teredo.bro | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/testing/btest/core/leaks/ayiya.test b/testing/btest/core/leaks/ayiya.test index 36e925951b..bf9f867cdd 100644 --- a/testing/btest/core/leaks/ayiya.test +++ b/testing/btest/core/leaks/ayiya.test @@ -5,4 +5,4 @@ # @TEST-GROUP: leaks # # @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -r $TRACES/tunnels/ayiya3.trace -# @TEST-EXEC: btest-bg-wait 15 +# @TEST-EXEC: btest-bg-wait 30 diff --git a/testing/btest/core/leaks/bloomfilter.bro b/testing/btest/core/leaks/bloomfilter.bro index 6d9b74114e..e35294f98c 100644 --- a/testing/btest/core/leaks/bloomfilter.bro +++ b/testing/btest/core/leaks/bloomfilter.bro @@ -5,7 +5,7 @@ # @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks # # @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -b -r $TRACES/wikipedia.trace %INPUT -# @TEST-EXEC: btest-bg-wait 15 +# @TEST-EXEC: btest-bg-wait 30 function test_basic_bloom_filter() { diff --git a/testing/btest/core/leaks/gridftp.test b/testing/btest/core/leaks/gridftp.test index b9a0a70127..f0ba6cf8e6 100644 --- a/testing/btest/core/leaks/gridftp.test +++ b/testing/btest/core/leaks/gridftp.test @@ -5,7 +5,7 @@ # @TEST-GROUP: leaks # # @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -r $TRACES/globus-url-copy.trace %INPUT -# @TEST-EXEC: btest-bg-wait 15 +# @TEST-EXEC: btest-bg-wait 30 @load base/protocols/ftp/gridftp diff --git a/testing/btest/core/leaks/gtp_opt_header.test b/testing/btest/core/leaks/gtp_opt_header.test index 771e4b3861..4205766ee0 100644 --- a/testing/btest/core/leaks/gtp_opt_header.test +++ b/testing/btest/core/leaks/gtp_opt_header.test @@ -5,7 +5,7 @@ # @TEST-GROUP: leaks # # @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -r $TRACES/tunnels/gtp/gtp6_gtp_0x32.pcap %INPUT >out -# @TEST-EXEC: btest-bg-wait 15 +# @TEST-EXEC: btest-bg-wait 30 # Some GTPv1 headers have some optional fields totaling to a 4-byte extension # of the mandatory header. diff --git a/testing/btest/core/leaks/input-reread.bro b/testing/btest/core/leaks/input-reread.bro index c6ff5361be..e9aab062d0 100644 --- a/testing/btest/core/leaks/input-reread.bro +++ b/testing/btest/core/leaks/input-reread.bro @@ -6,13 +6,13 @@ # # @TEST-EXEC: cp input1.log input.log # @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -b %INPUT -# @TEST-EXEC: sleep 5 +# @TEST-EXEC: sleep 10 # @TEST-EXEC: cp input2.log input.log -# @TEST-EXEC: sleep 5 +# @TEST-EXEC: sleep 10 # @TEST-EXEC: cp input3.log input.log -# @TEST-EXEC: sleep 5 +# @TEST-EXEC: sleep 10 # @TEST-EXEC: cp input4.log input.log -# @TEST-EXEC: sleep 5 +# @TEST-EXEC: sleep 10 # @TEST-EXEC: cp input5.log input.log # @TEST-EXEC: btest-bg-wait 30 diff --git a/testing/btest/core/leaks/teredo.bro b/testing/btest/core/leaks/teredo.bro index 69c961fec4..a97172271e 100644 --- a/testing/btest/core/leaks/teredo.bro +++ b/testing/btest/core/leaks/teredo.bro @@ -5,7 +5,7 @@ # @TEST-GROUP: leaks # # @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -r $TRACES/tunnels/Teredo.pcap %INPUT >output -# @TEST-EXEC: btest-bg-wait 15 +# @TEST-EXEC: btest-bg-wait 30 function print_teredo(name: string, outer: connection, inner: teredo_hdr) { From 1735e33691dad0d500f024300a0c2dfb716a3fdc Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Fri, 28 Feb 2014 02:09:06 -0800 Subject: [PATCH 095/254] Backport crash fix that made it into master with the x509_extension backport from here. --- src/file_analysis/analyzer/x509/X509.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/file_analysis/analyzer/x509/X509.cc b/src/file_analysis/analyzer/x509/X509.cc index 59ab644634..c2c2a0b8bc 100644 --- a/src/file_analysis/analyzer/x509/X509.cc +++ b/src/file_analysis/analyzer/x509/X509.cc @@ -163,10 +163,13 @@ void file_analysis::X509::ParseExtension(X509_EXTENSION* ex) BIO_flush(bio); int length = BIO_pending(bio); - char *buffer = new char[length]; + + // Use OPENSSL_malloc here. Using new or anything else can lead + // to interesting, hard to debug segfaults. + char *buffer = (char*) OPENSSL_malloc(length); BIO_read(bio, (void*)buffer, length); StringVal* ext_val = new StringVal(length, buffer); - delete(buffer); + OPENSSL_free(buffer); BIO_free_all(bio); RecordVal* pX509Ext = new RecordVal(BifType::Record::X509::Extension); @@ -189,16 +192,13 @@ void file_analysis::X509::ParseExtension(X509_EXTENSION* ex) mgr.QueueEvent(x509_extension, vl); - // look if we have a specialized handler for this event... if ( OBJ_obj2nid(ext_asn) == NID_basic_constraints ) ParseBasicConstraints(ex); else if ( OBJ_obj2nid(ext_asn) == NID_subject_alt_name ) ParseSAN(ex); - - - } + void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex) { assert(OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == NID_basic_constraints); @@ -222,7 +222,6 @@ void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex) mgr.QueueEvent(x509_ext_basic_constraints, vl); } - } void file_analysis::X509::ParseSAN(X509_EXTENSION* ext) From 7ba6bcff2ca20c5d57244b7e6f11a22c95520819 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Fri, 28 Feb 2014 02:43:16 -0800 Subject: [PATCH 096/254] Second try on the event interface. Now the x509 opaque is wrapped in the certificate structure. After pondering on it for a bit, this might not be the brightest idea. --- scripts/base/files/x509/main.bro | 6 +-- scripts/base/init-bare.bro | 25 +----------- src/NetVar.cc | 6 --- src/NetVar.h | 3 -- src/file_analysis/analyzer/x509/X509.cc | 45 ++++++++++++++-------- src/file_analysis/analyzer/x509/X509.h | 11 +++--- src/file_analysis/analyzer/x509/events.bif | 6 +-- 7 files changed, 40 insertions(+), 62 deletions(-) diff --git a/scripts/base/files/x509/main.bro b/scripts/base/files/x509/main.bro index 458a389934..d19327f07c 100644 --- a/scripts/base/files/x509/main.bro +++ b/scripts/base/files/x509/main.bro @@ -12,17 +12,17 @@ event x509_cert(f: fa_file, cert: X509::Certificate) print cert; } -event x509_extension(f: fa_file, ext: X509::Extension) +event x509_extension(f: fa_file, cert: X509::Certificate, ext: X509::Extension) { print ext; } -event x509_ext_basic_constraints(f: fa_file, ext: X509::BasicConstraints) +event x509_ext_basic_constraints(f: fa_file, cert: X509::Certificate, ext: X509::BasicConstraints) { print ext; } -event x509_ext_subject_alternative_name(f: fa_file, ext: X509::SubjectAlternativeName) +event x509_ext_subject_alternative_name(f: fa_file, cert: X509::Certificate, ext: X509::SubjectAlternativeName) { print ext; } diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 8573fc2876..e4c1803fcb 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2420,29 +2420,6 @@ global dns_skip_all_addl = T &redef; ## traffic and do not process it. Set to 0 to turn off this functionality. global dns_max_queries = 5; -## An X509 certificate. -## -## .. bro:see:: x509_certificate -type X509: record { - version: count; ##< Version number. - serial: string; ##< Serial number. - subject: string; ##< Subject. - issuer: string; ##< Issuer. - not_valid_before: time; ##< Timestamp before when certificate is not valid. - not_valid_after: time; ##< Timestamp after when certificate is not valid. -}; - -## An X509 extension. -## -## .. bro:see:: x509_extension -type X509_extension_info: record { - name: string; ##< Long name of extension; oid if name not known. - short_name: string &optional; ##< Short name of extension if known. - oid: string; ##< Oid of extension. - critical: bool; ##< True if extension is critical. - value: string; ##< Extension content parsed to string for known extensions. Raw data otherwise. -}; - ## HTTP session statistics. ## ## .. bro:see:: http_stats @@ -2767,6 +2744,7 @@ export { module X509; export { type X509::Certificate: record { + certificate: opaque of x509; ##< OpenSSL certificate reference version: count; ##< Version number. serial: string; ##< Serial number. subject: string; ##< Subject. @@ -2799,7 +2777,6 @@ export { type X509::SubjectAlternativeName: record { names: vector of string; }; - } module SOCKS; diff --git a/src/NetVar.cc b/src/NetVar.cc index 05a4e16b47..2883adcf9f 100644 --- a/src/NetVar.cc +++ b/src/NetVar.cc @@ -47,9 +47,6 @@ int tcp_max_initial_window; int tcp_max_above_hole_without_any_acks; int tcp_excessive_data_without_further_acks; -RecordType* x509_type; -RecordType* x509_extension_type; - RecordType* socks_address; double non_analyzed_lifetime; @@ -356,9 +353,6 @@ void init_net_var() tcp_excessive_data_without_further_acks = opt_internal_int("tcp_excessive_data_without_further_acks"); - x509_type = internal_type("X509")->AsRecordType(); - x509_extension_type = internal_type("X509_extension_info")->AsRecordType(); - socks_address = internal_type("SOCKS::Address")->AsRecordType(); non_analyzed_lifetime = opt_internal_double("non_analyzed_lifetime"); diff --git a/src/NetVar.h b/src/NetVar.h index 8ef6571313..55f3955fa4 100644 --- a/src/NetVar.h +++ b/src/NetVar.h @@ -50,9 +50,6 @@ extern int tcp_max_initial_window; extern int tcp_max_above_hole_without_any_acks; extern int tcp_excessive_data_without_further_acks; -extern RecordType* x509_type; -extern RecordType* x509_extension_type; - extern RecordType* socks_address; extern double non_analyzed_lifetime; diff --git a/src/file_analysis/analyzer/x509/X509.cc b/src/file_analysis/analyzer/x509/X509.cc index c2c2a0b8bc..684f4f54ba 100644 --- a/src/file_analysis/analyzer/x509/X509.cc +++ b/src/file_analysis/analyzer/x509/X509.cc @@ -49,7 +49,7 @@ bool file_analysis::X509::EndOfFile() return false; } - ParseCertificate(ssl_cert); + RecordVal* cert_record = ParseCertificate(ssl_cert); // cert_record takes ownership of ssl_cert // after parsing the certificate - parse the extensions... @@ -60,37 +60,43 @@ bool file_analysis::X509::EndOfFile() if ( !ex ) continue; - ParseExtension(ex); + ParseExtension(ex, cert_record); } - X509_free(ssl_cert); + // X509_free(ssl_cert); We do _not_ free the certificate here. It is refcounted + // inside the X509Val that is sent on in the cert record to scriptland. + // + // The certificate will be freed when the last X509Val is Unref'd. + + Unref(cert_record); // Unref the RecordVal that we kept around from ParseCertificate return false; } -void file_analysis::X509::ParseCertificate(::X509* ssl_cert) +RecordVal* file_analysis::X509::ParseCertificate(::X509* ssl_cert) { char buf[256]; // we need a buffer for some of the openssl functions - memset(buf, 0, 256); + memset(buf, 0, 256); RecordVal* pX509Cert = new RecordVal(BifType::Record::X509::Certificate); BIO *bio = BIO_new(BIO_s_mem()); - pX509Cert->Assign(0, new Val((uint64) X509_get_version(ssl_cert), TYPE_COUNT)); + pX509Cert->Assign(0, new X509Val(ssl_cert)); // take ownership for cleanup + pX509Cert->Assign(1, new Val((uint64) X509_get_version(ssl_cert), TYPE_COUNT)); i2a_ASN1_INTEGER(bio, X509_get_serialNumber(ssl_cert)); int len = BIO_read(bio, &(*buf), sizeof buf); - pX509Cert->Assign(1, new StringVal(len, buf)); + pX509Cert->Assign(2, new StringVal(len, buf)); X509_NAME_print_ex(bio, X509_get_subject_name(ssl_cert), 0, XN_FLAG_RFC2253); len = BIO_gets(bio, &(*buf), sizeof buf); - pX509Cert->Assign(2, new StringVal(len, buf)); + pX509Cert->Assign(3, new StringVal(len, buf)); X509_NAME_print_ex(bio, X509_get_issuer_name(ssl_cert), 0, XN_FLAG_RFC2253); len = BIO_gets(bio, &(*buf), sizeof buf); - pX509Cert->Assign(3, new StringVal(len, buf)); + pX509Cert->Assign(4, new StringVal(len, buf)); BIO_free(bio); - pX509Cert->Assign(4, new Val(get_time_from_asn1(X509_get_notBefore(ssl_cert)), TYPE_TIME)); - pX509Cert->Assign(5, new Val(get_time_from_asn1(X509_get_notAfter(ssl_cert)), TYPE_TIME)); + pX509Cert->Assign(5, new Val(get_time_from_asn1(X509_get_notBefore(ssl_cert)), TYPE_TIME)); + pX509Cert->Assign(6, new Val(get_time_from_asn1(X509_get_notAfter(ssl_cert)), TYPE_TIME)); // we only read 255 bytes because byte 256 is always 0. // if the string is longer than 255, that will be our null-termination, @@ -137,12 +143,14 @@ void file_analysis::X509::ParseCertificate(::X509* ssl_cert) val_list* vl = new val_list(); vl->append(GetFile()->GetVal()->Ref()); - vl->append(pX509Cert); + vl->append(pX509Cert->Ref()); // we Ref it here, because we want to keep a copy around for now... mgr.QueueEvent(x509_cert, vl); + + return pX509Cert; } -void file_analysis::X509::ParseExtension(X509_EXTENSION* ex) +void file_analysis::X509::ParseExtension(X509_EXTENSION* ex, RecordVal* r) { char name[256]; char oid[256]; @@ -188,18 +196,19 @@ void file_analysis::X509::ParseExtension(X509_EXTENSION* ex) // but I am not sure if there is a better way to do it... val_list* vl = new val_list(); vl->append(GetFile()->GetVal()->Ref()); + vl->append(r->Ref()); vl->append(pX509Ext); mgr.QueueEvent(x509_extension, vl); // look if we have a specialized handler for this event... if ( OBJ_obj2nid(ext_asn) == NID_basic_constraints ) - ParseBasicConstraints(ex); + ParseBasicConstraints(ex, r); else if ( OBJ_obj2nid(ext_asn) == NID_subject_alt_name ) - ParseSAN(ex); + ParseSAN(ex, r); } -void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex) +void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r) { assert(OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == NID_basic_constraints); @@ -217,6 +226,7 @@ void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex) } val_list* vl = new val_list(); vl->append(GetFile()->GetVal()->Ref()); + vl->append(r->Ref()); vl->append(pBasicConstraint); mgr.QueueEvent(x509_ext_basic_constraints, vl); @@ -224,7 +234,7 @@ void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex) } } -void file_analysis::X509::ParseSAN(X509_EXTENSION* ext) +void file_analysis::X509::ParseSAN(X509_EXTENSION* ext, RecordVal* r) { assert(OBJ_obj2nid(X509_EXTENSION_get_object(ext)) == NID_subject_alt_name); @@ -268,6 +278,7 @@ void file_analysis::X509::ParseSAN(X509_EXTENSION* ext) val_list* vl = new val_list(); vl->append(GetFile()->GetVal()->Ref()); + vl->append(r->Ref()); vl->append(pSan); mgr.QueueEvent(x509_ext_basic_constraints, vl); diff --git a/src/file_analysis/analyzer/x509/X509.h b/src/file_analysis/analyzer/x509/X509.h index 80bb68209e..f64aa3eb58 100644 --- a/src/file_analysis/analyzer/x509/X509.h +++ b/src/file_analysis/analyzer/x509/X509.h @@ -31,10 +31,10 @@ private: static StringVal* key_curve(EVP_PKEY *key); static unsigned int key_length(EVP_PKEY *key); - void ParseCertificate(::X509* ssl_cert); - void ParseExtension(X509_EXTENSION* ex); - void ParseBasicConstraints(X509_EXTENSION* ex); - void ParseSAN(X509_EXTENSION* ex); + RecordVal* ParseCertificate(::X509* ssl_cert); + void ParseExtension(X509_EXTENSION* ex, RecordVal* r); + void ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r); + void ParseSAN(X509_EXTENSION* ex, RecordVal* r); std::string cert_data; }; @@ -55,7 +55,7 @@ public: * * @return A newly initialized X509Val */ - X509Val(::X509* certificate); + explicit X509Val(::X509* certificate); /** * Destructor. @@ -84,5 +84,4 @@ private: } - #endif diff --git a/src/file_analysis/analyzer/x509/events.bif b/src/file_analysis/analyzer/x509/events.bif index 148d09ec00..2787746e0c 100644 --- a/src/file_analysis/analyzer/x509/events.bif +++ b/src/file_analysis/analyzer/x509/events.bif @@ -1,4 +1,4 @@ event x509_cert%(f: fa_file, cert: X509::Certificate%); -event x509_extension%(f: fa_file, ext: X509::Extension%); -event x509_ext_basic_constraints%(f: fa_file, ext: X509::BasicConstraints%); -event x509_ext_subject_alternative_name%(f: fa_file, ext: X509::SubjectAlternativeName%); +event x509_extension%(f: fa_file, cert: X509::Certificate, ext: X509::Extension%); +event x509_ext_basic_constraints%(f: fa_file, cert: X509::Certificate, ext: X509::BasicConstraints%); +event x509_ext_subject_alternative_name%(f: fa_file, cert: X509::Certificate, ext: X509::SubjectAlternativeName%); From a1d91509641c1b5ed3808635dfc411f8be6ed39d Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Fri, 28 Feb 2014 03:40:18 -0800 Subject: [PATCH 097/254] Update mozilla root bundle --- scripts/base/protocols/ssl/mozilla-ca-list.bro | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/scripts/base/protocols/ssl/mozilla-ca-list.bro b/scripts/base/protocols/ssl/mozilla-ca-list.bro index d7c5578166..7450692fdd 100644 --- a/scripts/base/protocols/ssl/mozilla-ca-list.bro +++ b/scripts/base/protocols/ssl/mozilla-ca-list.bro @@ -1,5 +1,5 @@ # Don't edit! This file is automatically generated. -# Generated at: 2013-11-01 05:23:08 -0700 +# Generated at: 2014-02-28 03:34:22 -0800 # Generated from: http://mxr.mozilla.org/mozilla-central/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 # # The original source file comes with this licensing statement: @@ -11,7 +11,6 @@ @load base/protocols/ssl module SSL; redef root_certs += { - ["CN=GTE CyberTrust Global Root,OU=GTE CyberTrust Solutions\, Inc.,O=GTE Corporation,C=US"] = "\x30\x82\x02\x5A\x30\x82\x01\xC3\x02\x02\x01\xA5\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x30\x75\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x18\x30\x16\x06\x03\x55\x04\x0A\x13\x0F\x47\x54\x45\x20\x43\x6F\x72\x70\x6F\x72\x61\x74\x69\x6F\x6E\x31\x27\x30\x25\x06\x03\x55\x04\x0B\x13\x1E\x47\x54\x45\x20\x43\x79\x62\x65\x72\x54\x72\x75\x73\x74\x20\x53\x6F\x6C\x75\x74\x69\x6F\x6E\x73\x2C\x20\x49\x6E\x63\x2E\x31\x23\x30\x21\x06\x03\x55\x04\x03\x13\x1A\x47\x54\x45\x20\x43\x79\x62\x65\x72\x54\x72\x75\x73\x74\x20\x47\x6C\x6F\x62\x61\x6C\x20\x52\x6F\x6F\x74\x30\x1E\x17\x0D\x39\x38\x30\x38\x31\x33\x30\x30\x32\x39\x30\x30\x5A\x17\x0D\x31\x38\x30\x38\x31\x33\x32\x33\x35\x39\x30\x30\x5A\x30\x75\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x18\x30\x16\x06\x03\x55\x04\x0A\x13\x0F\x47\x54\x45\x20\x43\x6F\x72\x70\x6F\x72\x61\x74\x69\x6F\x6E\x31\x27\x30\x25\x06\x03\x55\x04\x0B\x13\x1E\x47\x54\x45\x20\x43\x79\x62\x65\x72\x54\x72\x75\x73\x74\x20\x53\x6F\x6C\x75\x74\x69\x6F\x6E\x73\x2C\x20\x49\x6E\x63\x2E\x31\x23\x30\x21\x06\x03\x55\x04\x03\x13\x1A\x47\x54\x45\x20\x43\x79\x62\x65\x72\x54\x72\x75\x73\x74\x20\x47\x6C\x6F\x62\x61\x6C\x20\x52\x6F\x6F\x74\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\x95\x0F\xA0\xB6\xF0\x50\x9C\xE8\x7A\xC7\x88\xCD\xDD\x17\x0E\x2E\xB0\x94\xD0\x1B\x3D\x0E\xF6\x94\xC0\x8A\x94\xC7\x06\xC8\x90\x97\xC8\xB8\x64\x1A\x7A\x7E\x6C\x3C\x53\xE1\x37\x28\x73\x60\x7F\xB2\x97\x53\x07\x9F\x53\xF9\x6D\x58\x94\xD2\xAF\x8D\x6D\x88\x67\x80\xE6\xED\xB2\x95\xCF\x72\x31\xCA\xA5\x1C\x72\xBA\x5C\x02\xE7\x64\x42\xE7\xF9\xA9\x2C\xD6\x3A\x0D\xAC\x8D\x42\xAA\x24\x01\x39\xE6\x9C\x3F\x01\x85\x57\x0D\x58\x87\x45\xF8\xD3\x85\xAA\x93\x69\x26\x85\x70\x48\x80\x3F\x12\x15\xC7\x79\xB4\x1F\x05\x2F\x3B\x62\x99\x02\x03\x01\x00\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x03\x81\x81\x00\x6D\xEB\x1B\x09\xE9\x5E\xD9\x51\xDB\x67\x22\x61\xA4\x2A\x3C\x48\x77\xE3\xA0\x7C\xA6\xDE\x73\xA2\x14\x03\x85\x3D\xFB\xAB\x0E\x30\xC5\x83\x16\x33\x81\x13\x08\x9E\x7B\x34\x4E\xDF\x40\xC8\x74\xD7\xB9\x7D\xDC\xF4\x76\x55\x7D\x9B\x63\x54\x18\xE9\xF0\xEA\xF3\x5C\xB1\xD9\x8B\x42\x1E\xB9\xC0\x95\x4E\xBA\xFA\xD5\xE2\x7C\xF5\x68\x61\xBF\x8E\xEC\x05\x97\x5F\x5B\xB0\xD7\xA3\x85\x34\xC4\x24\xA7\x0D\x0F\x95\x93\xEF\xCB\x94\xD8\x9E\x1F\x9D\x5C\x85\x6D\xC7\xAA\xAE\x4F\x1F\x22\xB5\xCD\x95\xAD\xBA\xA7\xCC\xF9\xAB\x0B\x7A\x7F", ["emailAddress=server-certs@thawte.com,CN=Thawte Server CA,OU=Certification Services Division,O=Thawte Consulting cc,L=Cape Town,ST=Western Cape,C=ZA"] = "\x30\x82\x03\x13\x30\x82\x02\x7C\xA0\x03\x02\x01\x02\x02\x01\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x30\x81\xC4\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x5A\x41\x31\x15\x30\x13\x06\x03\x55\x04\x08\x13\x0C\x57\x65\x73\x74\x65\x72\x6E\x20\x43\x61\x70\x65\x31\x12\x30\x10\x06\x03\x55\x04\x07\x13\x09\x43\x61\x70\x65\x20\x54\x6F\x77\x6E\x31\x1D\x30\x1B\x06\x03\x55\x04\x0A\x13\x14\x54\x68\x61\x77\x74\x65\x20\x43\x6F\x6E\x73\x75\x6C\x74\x69\x6E\x67\x20\x63\x63\x31\x28\x30\x26\x06\x03\x55\x04\x0B\x13\x1F\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x53\x65\x72\x76\x69\x63\x65\x73\x20\x44\x69\x76\x69\x73\x69\x6F\x6E\x31\x19\x30\x17\x06\x03\x55\x04\x03\x13\x10\x54\x68\x61\x77\x74\x65\x20\x53\x65\x72\x76\x65\x72\x20\x43\x41\x31\x26\x30\x24\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x17\x73\x65\x72\x76\x65\x72\x2D\x63\x65\x72\x74\x73\x40\x74\x68\x61\x77\x74\x65\x2E\x63\x6F\x6D\x30\x1E\x17\x0D\x39\x36\x30\x38\x30\x31\x30\x30\x30\x30\x30\x30\x5A\x17\x0D\x32\x30\x31\x32\x33\x31\x32\x33\x35\x39\x35\x39\x5A\x30\x81\xC4\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x5A\x41\x31\x15\x30\x13\x06\x03\x55\x04\x08\x13\x0C\x57\x65\x73\x74\x65\x72\x6E\x20\x43\x61\x70\x65\x31\x12\x30\x10\x06\x03\x55\x04\x07\x13\x09\x43\x61\x70\x65\x20\x54\x6F\x77\x6E\x31\x1D\x30\x1B\x06\x03\x55\x04\x0A\x13\x14\x54\x68\x61\x77\x74\x65\x20\x43\x6F\x6E\x73\x75\x6C\x74\x69\x6E\x67\x20\x63\x63\x31\x28\x30\x26\x06\x03\x55\x04\x0B\x13\x1F\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x53\x65\x72\x76\x69\x63\x65\x73\x20\x44\x69\x76\x69\x73\x69\x6F\x6E\x31\x19\x30\x17\x06\x03\x55\x04\x03\x13\x10\x54\x68\x61\x77\x74\x65\x20\x53\x65\x72\x76\x65\x72\x20\x43\x41\x31\x26\x30\x24\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x17\x73\x65\x72\x76\x65\x72\x2D\x63\x65\x72\x74\x73\x40\x74\x68\x61\x77\x74\x65\x2E\x63\x6F\x6D\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\xD3\xA4\x50\x6E\xC8\xFF\x56\x6B\xE6\xCF\x5D\xB6\xEA\x0C\x68\x75\x47\xA2\xAA\xC2\xDA\x84\x25\xFC\xA8\xF4\x47\x51\xDA\x85\xB5\x20\x74\x94\x86\x1E\x0F\x75\xC9\xE9\x08\x61\xF5\x06\x6D\x30\x6E\x15\x19\x02\xE9\x52\xC0\x62\xDB\x4D\x99\x9E\xE2\x6A\x0C\x44\x38\xCD\xFE\xBE\xE3\x64\x09\x70\xC5\xFE\xB1\x6B\x29\xB6\x2F\x49\xC8\x3B\xD4\x27\x04\x25\x10\x97\x2F\xE7\x90\x6D\xC0\x28\x42\x99\xD7\x4C\x43\xDE\xC3\xF5\x21\x6D\x54\x9F\x5D\xC3\x58\xE1\xC0\xE4\xD9\x5B\xB0\xB8\xDC\xB4\x7B\xDF\x36\x3A\xC2\xB5\x66\x22\x12\xD6\x87\x0D\x02\x03\x01\x00\x01\xA3\x13\x30\x11\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x03\x81\x81\x00\x07\xFA\x4C\x69\x5C\xFB\x95\xCC\x46\xEE\x85\x83\x4D\x21\x30\x8E\xCA\xD9\xA8\x6F\x49\x1A\xE6\xDA\x51\xE3\x60\x70\x6C\x84\x61\x11\xA1\x1A\xC8\x48\x3E\x59\x43\x7D\x4F\x95\x3D\xA1\x8B\xB7\x0B\x62\x98\x7A\x75\x8A\xDD\x88\x4E\x4E\x9E\x40\xDB\xA8\xCC\x32\x74\xB9\x6F\x0D\xC6\xE3\xB3\x44\x0B\xD9\x8A\x6F\x9A\x29\x9B\x99\x18\x28\x3B\xD1\xE3\x40\x28\x9A\x5A\x3C\xD5\xB5\xE7\x20\x1B\x8B\xCA\xA4\xAB\x8D\xE9\x51\xD9\xE2\x4C\x2C\x59\xA9\xDA\xB9\xB2\x75\x1B\xF6\x42\xF2\xEF\xC7\xF2\x18\xF9\x89\xBC\xA3\xFF\x8A\x23\x2E\x70\x47", ["emailAddress=premium-server@thawte.com,CN=Thawte Premium Server CA,OU=Certification Services Division,O=Thawte Consulting cc,L=Cape Town,ST=Western Cape,C=ZA"] = "\x30\x82\x03\x27\x30\x82\x02\x90\xA0\x03\x02\x01\x02\x02\x01\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x30\x81\xCE\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x5A\x41\x31\x15\x30\x13\x06\x03\x55\x04\x08\x13\x0C\x57\x65\x73\x74\x65\x72\x6E\x20\x43\x61\x70\x65\x31\x12\x30\x10\x06\x03\x55\x04\x07\x13\x09\x43\x61\x70\x65\x20\x54\x6F\x77\x6E\x31\x1D\x30\x1B\x06\x03\x55\x04\x0A\x13\x14\x54\x68\x61\x77\x74\x65\x20\x43\x6F\x6E\x73\x75\x6C\x74\x69\x6E\x67\x20\x63\x63\x31\x28\x30\x26\x06\x03\x55\x04\x0B\x13\x1F\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x53\x65\x72\x76\x69\x63\x65\x73\x20\x44\x69\x76\x69\x73\x69\x6F\x6E\x31\x21\x30\x1F\x06\x03\x55\x04\x03\x13\x18\x54\x68\x61\x77\x74\x65\x20\x50\x72\x65\x6D\x69\x75\x6D\x20\x53\x65\x72\x76\x65\x72\x20\x43\x41\x31\x28\x30\x26\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x19\x70\x72\x65\x6D\x69\x75\x6D\x2D\x73\x65\x72\x76\x65\x72\x40\x74\x68\x61\x77\x74\x65\x2E\x63\x6F\x6D\x30\x1E\x17\x0D\x39\x36\x30\x38\x30\x31\x30\x30\x30\x30\x30\x30\x5A\x17\x0D\x32\x30\x31\x32\x33\x31\x32\x33\x35\x39\x35\x39\x5A\x30\x81\xCE\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x5A\x41\x31\x15\x30\x13\x06\x03\x55\x04\x08\x13\x0C\x57\x65\x73\x74\x65\x72\x6E\x20\x43\x61\x70\x65\x31\x12\x30\x10\x06\x03\x55\x04\x07\x13\x09\x43\x61\x70\x65\x20\x54\x6F\x77\x6E\x31\x1D\x30\x1B\x06\x03\x55\x04\x0A\x13\x14\x54\x68\x61\x77\x74\x65\x20\x43\x6F\x6E\x73\x75\x6C\x74\x69\x6E\x67\x20\x63\x63\x31\x28\x30\x26\x06\x03\x55\x04\x0B\x13\x1F\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x53\x65\x72\x76\x69\x63\x65\x73\x20\x44\x69\x76\x69\x73\x69\x6F\x6E\x31\x21\x30\x1F\x06\x03\x55\x04\x03\x13\x18\x54\x68\x61\x77\x74\x65\x20\x50\x72\x65\x6D\x69\x75\x6D\x20\x53\x65\x72\x76\x65\x72\x20\x43\x41\x31\x28\x30\x26\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x19\x70\x72\x65\x6D\x69\x75\x6D\x2D\x73\x65\x72\x76\x65\x72\x40\x74\x68\x61\x77\x74\x65\x2E\x63\x6F\x6D\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\xD2\x36\x36\x6A\x8B\xD7\xC2\x5B\x9E\xDA\x81\x41\x62\x8F\x38\xEE\x49\x04\x55\xD6\xD0\xEF\x1C\x1B\x95\x16\x47\xEF\x18\x48\x35\x3A\x52\xF4\x2B\x6A\x06\x8F\x3B\x2F\xEA\x56\xE3\xAF\x86\x8D\x9E\x17\xF7\x9E\xB4\x65\x75\x02\x4D\xEF\xCB\x09\xA2\x21\x51\xD8\x9B\xD0\x67\xD0\xBA\x0D\x92\x06\x14\x73\xD4\x93\xCB\x97\x2A\x00\x9C\x5C\x4E\x0C\xBC\xFA\x15\x52\xFC\xF2\x44\x6E\xDA\x11\x4A\x6E\x08\x9F\x2F\x2D\xE3\xF9\xAA\x3A\x86\x73\xB6\x46\x53\x58\xC8\x89\x05\xBD\x83\x11\xB8\x73\x3F\xAA\x07\x8D\xF4\x42\x4D\xE7\x40\x9D\x1C\x37\x02\x03\x01\x00\x01\xA3\x13\x30\x11\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x03\x81\x81\x00\x26\x48\x2C\x16\xC2\x58\xFA\xE8\x16\x74\x0C\xAA\xAA\x5F\x54\x3F\xF2\xD7\xC9\x78\x60\x5E\x5E\x6E\x37\x63\x22\x77\x36\x7E\xB2\x17\xC4\x34\xB9\xF5\x08\x85\xFC\xC9\x01\x38\xFF\x4D\xBE\xF2\x16\x42\x43\xE7\xBB\x5A\x46\xFB\xC1\xC6\x11\x1F\xF1\x4A\xB0\x28\x46\xC9\xC3\xC4\x42\x7D\xBC\xFA\xAB\x59\x6E\xD5\xB7\x51\x88\x11\xE3\xA4\x85\x19\x6B\x82\x4C\xA4\x0C\x12\xAD\xE9\xA4\xAE\x3F\xF1\xC3\x49\x65\x9A\x8C\xC5\xC8\x3E\x25\xB7\x94\x99\xBB\x92\x32\x71\x07\xF0\x86\x5E\xED\x50\x27\xA6\x0D\xA6\x23\xF9\xBB\xCB\xA6\x07\x14\x42", ["OU=Equifax Secure Certificate Authority,O=Equifax,C=US"] = "\x30\x82\x03\x20\x30\x82\x02\x89\xA0\x03\x02\x01\x02\x02\x04\x35\xDE\xF4\xCF\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x4E\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x10\x30\x0E\x06\x03\x55\x04\x0A\x13\x07\x45\x71\x75\x69\x66\x61\x78\x31\x2D\x30\x2B\x06\x03\x55\x04\x0B\x13\x24\x45\x71\x75\x69\x66\x61\x78\x20\x53\x65\x63\x75\x72\x65\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x1E\x17\x0D\x39\x38\x30\x38\x32\x32\x31\x36\x34\x31\x35\x31\x5A\x17\x0D\x31\x38\x30\x38\x32\x32\x31\x36\x34\x31\x35\x31\x5A\x30\x4E\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x10\x30\x0E\x06\x03\x55\x04\x0A\x13\x07\x45\x71\x75\x69\x66\x61\x78\x31\x2D\x30\x2B\x06\x03\x55\x04\x0B\x13\x24\x45\x71\x75\x69\x66\x61\x78\x20\x53\x65\x63\x75\x72\x65\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\xC1\x5D\xB1\x58\x67\x08\x62\xEE\xA0\x9A\x2D\x1F\x08\x6D\x91\x14\x68\x98\x0A\x1E\xFE\xDA\x04\x6F\x13\x84\x62\x21\xC3\xD1\x7C\xCE\x9F\x05\xE0\xB8\x01\xF0\x4E\x34\xEC\xE2\x8A\x95\x04\x64\xAC\xF1\x6B\x53\x5F\x05\xB3\xCB\x67\x80\xBF\x42\x02\x8E\xFE\xDD\x01\x09\xEC\xE1\x00\x14\x4F\xFC\xFB\xF0\x0C\xDD\x43\xBA\x5B\x2B\xE1\x1F\x80\x70\x99\x15\x57\x93\x16\xF1\x0F\x97\x6A\xB7\xC2\x68\x23\x1C\xCC\x4D\x59\x30\xAC\x51\x1E\x3B\xAF\x2B\xD6\xEE\x63\x45\x7B\xC5\xD9\x5F\x50\xD2\xE3\x50\x0F\x3A\x88\xE7\xBF\x14\xFD\xE0\xC7\xB9\x02\x03\x01\x00\x01\xA3\x82\x01\x09\x30\x82\x01\x05\x30\x70\x06\x03\x55\x1D\x1F\x04\x69\x30\x67\x30\x65\xA0\x63\xA0\x61\xA4\x5F\x30\x5D\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x10\x30\x0E\x06\x03\x55\x04\x0A\x13\x07\x45\x71\x75\x69\x66\x61\x78\x31\x2D\x30\x2B\x06\x03\x55\x04\x0B\x13\x24\x45\x71\x75\x69\x66\x61\x78\x20\x53\x65\x63\x75\x72\x65\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x31\x0D\x30\x0B\x06\x03\x55\x04\x03\x13\x04\x43\x52\x4C\x31\x30\x1A\x06\x03\x55\x1D\x10\x04\x13\x30\x11\x81\x0F\x32\x30\x31\x38\x30\x38\x32\x32\x31\x36\x34\x31\x35\x31\x5A\x30\x0B\x06\x03\x55\x1D\x0F\x04\x04\x03\x02\x01\x06\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\x48\xE6\x68\xF9\x2B\xD2\xB2\x95\xD7\x47\xD8\x23\x20\x10\x4F\x33\x98\x90\x9F\xD4\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x48\xE6\x68\xF9\x2B\xD2\xB2\x95\xD7\x47\xD8\x23\x20\x10\x4F\x33\x98\x90\x9F\xD4\x30\x0C\x06\x03\x55\x1D\x13\x04\x05\x30\x03\x01\x01\xFF\x30\x1A\x06\x09\x2A\x86\x48\x86\xF6\x7D\x07\x41\x00\x04\x0D\x30\x0B\x1B\x05\x56\x33\x2E\x30\x63\x03\x02\x06\xC0\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x81\x81\x00\x58\xCE\x29\xEA\xFC\xF7\xDE\xB5\xCE\x02\xB9\x17\xB5\x85\xD1\xB9\xE3\xE0\x95\xCC\x25\x31\x0D\x00\xA6\x92\x6E\x7F\xB6\x92\x63\x9E\x50\x95\xD1\x9A\x6F\xE4\x11\xDE\x63\x85\x6E\x98\xEE\xA8\xFF\x5A\xC8\xD3\x55\xB2\x66\x71\x57\xDE\xC0\x21\xEB\x3D\x2A\xA7\x23\x49\x01\x04\x86\x42\x7B\xFC\xEE\x7F\xA2\x16\x52\xB5\x67\x67\xD3\x40\xDB\x3B\x26\x58\xB2\x28\x77\x3D\xAE\x14\x77\x61\xD6\xFA\x2A\x66\x27\xA0\x0D\xFA\xA7\x73\x5C\xEA\x70\xF1\x94\x21\x65\x44\x5F\xFA\xFC\xEF\x29\x68\xA9\xA2\x87\x79\xEF\x79\xEF\x4F\xAC\x07\x77\x38", @@ -19,12 +18,8 @@ redef root_certs += { ["OU=VeriSign Trust Network,OU=(c) 1998 VeriSign\, Inc. - For authorized use only,OU=Class 3 Public Primary Certification Authority - G2,O=VeriSign\, Inc.,C=US"] = "\x30\x82\x03\x02\x30\x82\x02\x6B\x02\x10\x7D\xD9\xFE\x07\xCF\xA8\x1E\xB7\x10\x79\x67\xFB\xA7\x89\x34\xC6\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x81\xC1\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x31\x3C\x30\x3A\x06\x03\x55\x04\x0B\x13\x33\x43\x6C\x61\x73\x73\x20\x33\x20\x50\x75\x62\x6C\x69\x63\x20\x50\x72\x69\x6D\x61\x72\x79\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x20\x2D\x20\x47\x32\x31\x3A\x30\x38\x06\x03\x55\x04\x0B\x13\x31\x28\x63\x29\x20\x31\x39\x39\x38\x20\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x20\x2D\x20\x46\x6F\x72\x20\x61\x75\x74\x68\x6F\x72\x69\x7A\x65\x64\x20\x75\x73\x65\x20\x6F\x6E\x6C\x79\x31\x1F\x30\x1D\x06\x03\x55\x04\x0B\x13\x16\x56\x65\x72\x69\x53\x69\x67\x6E\x20\x54\x72\x75\x73\x74\x20\x4E\x65\x74\x77\x6F\x72\x6B\x30\x1E\x17\x0D\x39\x38\x30\x35\x31\x38\x30\x30\x30\x30\x30\x30\x5A\x17\x0D\x32\x38\x30\x38\x30\x31\x32\x33\x35\x39\x35\x39\x5A\x30\x81\xC1\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x31\x3C\x30\x3A\x06\x03\x55\x04\x0B\x13\x33\x43\x6C\x61\x73\x73\x20\x33\x20\x50\x75\x62\x6C\x69\x63\x20\x50\x72\x69\x6D\x61\x72\x79\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x20\x2D\x20\x47\x32\x31\x3A\x30\x38\x06\x03\x55\x04\x0B\x13\x31\x28\x63\x29\x20\x31\x39\x39\x38\x20\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x20\x2D\x20\x46\x6F\x72\x20\x61\x75\x74\x68\x6F\x72\x69\x7A\x65\x64\x20\x75\x73\x65\x20\x6F\x6E\x6C\x79\x31\x1F\x30\x1D\x06\x03\x55\x04\x0B\x13\x16\x56\x65\x72\x69\x53\x69\x67\x6E\x20\x54\x72\x75\x73\x74\x20\x4E\x65\x74\x77\x6F\x72\x6B\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\xCC\x5E\xD1\x11\x5D\x5C\x69\xD0\xAB\xD3\xB9\x6A\x4C\x99\x1F\x59\x98\x30\x8E\x16\x85\x20\x46\x6D\x47\x3F\xD4\x85\x20\x84\xE1\x6D\xB3\xF8\xA4\xED\x0C\xF1\x17\x0F\x3B\xF9\xA7\xF9\x25\xD7\xC1\xCF\x84\x63\xF2\x7C\x63\xCF\xA2\x47\xF2\xC6\x5B\x33\x8E\x64\x40\x04\x68\xC1\x80\xB9\x64\x1C\x45\x77\xC7\xD8\x6E\xF5\x95\x29\x3C\x50\xE8\x34\xD7\x78\x1F\xA8\xBA\x6D\x43\x91\x95\x8F\x45\x57\x5E\x7E\xC5\xFB\xCA\xA4\x04\xEB\xEA\x97\x37\x54\x30\x6F\xBB\x01\x47\x32\x33\xCD\xDC\x57\x9B\x64\x69\x61\xF8\x9B\x1D\x1C\x89\x4F\x5C\x67\x02\x03\x01\x00\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x81\x81\x00\x51\x4D\xCD\xBE\x5C\xCB\x98\x19\x9C\x15\xB2\x01\x39\x78\x2E\x4D\x0F\x67\x70\x70\x99\xC6\x10\x5A\x94\xA4\x53\x4D\x54\x6D\x2B\xAF\x0D\x5D\x40\x8B\x64\xD3\xD7\xEE\xDE\x56\x61\x92\x5F\xA6\xC4\x1D\x10\x61\x36\xD3\x2C\x27\x3C\xE8\x29\x09\xB9\x11\x64\x74\xCC\xB5\x73\x9F\x1C\x48\xA9\xBC\x61\x01\xEE\xE2\x17\xA6\x0C\xE3\x40\x08\x3B\x0E\xE7\xEB\x44\x73\x2A\x9A\xF1\x69\x92\xEF\x71\x14\xC3\x39\xAC\x71\xA7\x91\x09\x6F\xE4\x71\x06\xB3\xBA\x59\x57\x26\x79\x00\xF6\xF8\x0D\xA2\x33\x30\x28\xD4\xAA\x58\xA0\x9D\x9D\x69\x91\xFD", ["CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE"] = "\x30\x82\x03\x75\x30\x82\x02\x5D\xA0\x03\x02\x01\x02\x02\x0B\x04\x00\x00\x00\x00\x01\x15\x4B\x5A\xC3\x94\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x57\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x42\x45\x31\x19\x30\x17\x06\x03\x55\x04\x0A\x13\x10\x47\x6C\x6F\x62\x61\x6C\x53\x69\x67\x6E\x20\x6E\x76\x2D\x73\x61\x31\x10\x30\x0E\x06\x03\x55\x04\x0B\x13\x07\x52\x6F\x6F\x74\x20\x43\x41\x31\x1B\x30\x19\x06\x03\x55\x04\x03\x13\x12\x47\x6C\x6F\x62\x61\x6C\x53\x69\x67\x6E\x20\x52\x6F\x6F\x74\x20\x43\x41\x30\x1E\x17\x0D\x39\x38\x30\x39\x30\x31\x31\x32\x30\x30\x30\x30\x5A\x17\x0D\x32\x38\x30\x31\x32\x38\x31\x32\x30\x30\x30\x30\x5A\x30\x57\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x42\x45\x31\x19\x30\x17\x06\x03\x55\x04\x0A\x13\x10\x47\x6C\x6F\x62\x61\x6C\x53\x69\x67\x6E\x20\x6E\x76\x2D\x73\x61\x31\x10\x30\x0E\x06\x03\x55\x04\x0B\x13\x07\x52\x6F\x6F\x74\x20\x43\x41\x31\x1B\x30\x19\x06\x03\x55\x04\x03\x13\x12\x47\x6C\x6F\x62\x61\x6C\x53\x69\x67\x6E\x20\x52\x6F\x6F\x74\x20\x43\x41\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xDA\x0E\xE6\x99\x8D\xCE\xA3\xE3\x4F\x8A\x7E\xFB\xF1\x8B\x83\x25\x6B\xEA\x48\x1F\xF1\x2A\xB0\xB9\x95\x11\x04\xBD\xF0\x63\xD1\xE2\x67\x66\xCF\x1C\xDD\xCF\x1B\x48\x2B\xEE\x8D\x89\x8E\x9A\xAF\x29\x80\x65\xAB\xE9\xC7\x2D\x12\xCB\xAB\x1C\x4C\x70\x07\xA1\x3D\x0A\x30\xCD\x15\x8D\x4F\xF8\xDD\xD4\x8C\x50\x15\x1C\xEF\x50\xEE\xC4\x2E\xF7\xFC\xE9\x52\xF2\x91\x7D\xE0\x6D\xD5\x35\x30\x8E\x5E\x43\x73\xF2\x41\xE9\xD5\x6A\xE3\xB2\x89\x3A\x56\x39\x38\x6F\x06\x3C\x88\x69\x5B\x2A\x4D\xC5\xA7\x54\xB8\x6C\x89\xCC\x9B\xF9\x3C\xCA\xE5\xFD\x89\xF5\x12\x3C\x92\x78\x96\xD6\xDC\x74\x6E\x93\x44\x61\xD1\x8D\xC7\x46\xB2\x75\x0E\x86\xE8\x19\x8A\xD5\x6D\x6C\xD5\x78\x16\x95\xA2\xE9\xC8\x0A\x38\xEB\xF2\x24\x13\x4F\x73\x54\x93\x13\x85\x3A\x1B\xBC\x1E\x34\xB5\x8B\x05\x8C\xB9\x77\x8B\xB1\xDB\x1F\x20\x91\xAB\x09\x53\x6E\x90\xCE\x7B\x37\x74\xB9\x70\x47\x91\x22\x51\x63\x16\x79\xAE\xB1\xAE\x41\x26\x08\xC8\x19\x2B\xD1\x46\xAA\x48\xD6\x64\x2A\xD7\x83\x34\xFF\x2C\x2A\xC1\x6C\x19\x43\x4A\x07\x85\xE7\xD3\x7C\xF6\x21\x68\xEF\xEA\xF2\x52\x9F\x7F\x93\x90\xCF\x02\x03\x01\x00\x01\xA3\x42\x30\x40\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x60\x7B\x66\x1A\x45\x0D\x97\xCA\x89\x50\x2F\x7D\x04\xCD\x34\xA8\xFF\xFC\xFD\x4B\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\xD6\x73\xE7\x7C\x4F\x76\xD0\x8D\xBF\xEC\xBA\xA2\xBE\x34\xC5\x28\x32\xB5\x7C\xFC\x6C\x9C\x2C\x2B\xBD\x09\x9E\x53\xBF\x6B\x5E\xAA\x11\x48\xB6\xE5\x08\xA3\xB3\xCA\x3D\x61\x4D\xD3\x46\x09\xB3\x3E\xC3\xA0\xE3\x63\x55\x1B\xF2\xBA\xEF\xAD\x39\xE1\x43\xB9\x38\xA3\xE6\x2F\x8A\x26\x3B\xEF\xA0\x50\x56\xF9\xC6\x0A\xFD\x38\xCD\xC4\x0B\x70\x51\x94\x97\x98\x04\xDF\xC3\x5F\x94\xD5\x15\xC9\x14\x41\x9C\xC4\x5D\x75\x64\x15\x0D\xFF\x55\x30\xEC\x86\x8F\xFF\x0D\xEF\x2C\xB9\x63\x46\xF6\xAA\xFC\xDF\xBC\x69\xFD\x2E\x12\x48\x64\x9A\xE0\x95\xF0\xA6\xEF\x29\x8F\x01\xB1\x15\xB5\x0C\x1D\xA5\xFE\x69\x2C\x69\x24\x78\x1E\xB3\xA7\x1C\x71\x62\xEE\xCA\xC8\x97\xAC\x17\x5D\x8A\xC2\xF8\x47\x86\x6E\x2A\xC4\x56\x31\x95\xD0\x67\x89\x85\x2B\xF9\x6C\xA6\x5D\x46\x9D\x0C\xAA\x82\xE4\x99\x51\xDD\x70\xB7\xDB\x56\x3D\x61\xE4\x6A\xE1\x5C\xD6\xF6\xFE\x3D\xDE\x41\xCC\x07\xAE\x63\x52\xBF\x53\x53\xF4\x2B\xE9\xC7\xFD\xB6\xF7\x82\x5F\x85\xD2\x41\x18\xDB\x81\xB3\x04\x1C\xC5\x1F\xA4\x80\x6F\x15\x20\xC9\xDE\x0C\x88\x0A\x1D\xD6\x66\x55\xE2\xFC\x48\xC9\x29\x26\x69\xE0", ["CN=GlobalSign,O=GlobalSign,OU=GlobalSign Root CA - R2"] = "\x30\x82\x03\xBA\x30\x82\x02\xA2\xA0\x03\x02\x01\x02\x02\x0B\x04\x00\x00\x00\x00\x01\x0F\x86\x26\xE6\x0D\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x4C\x31\x20\x30\x1E\x06\x03\x55\x04\x0B\x13\x17\x47\x6C\x6F\x62\x61\x6C\x53\x69\x67\x6E\x20\x52\x6F\x6F\x74\x20\x43\x41\x20\x2D\x20\x52\x32\x31\x13\x30\x11\x06\x03\x55\x04\x0A\x13\x0A\x47\x6C\x6F\x62\x61\x6C\x53\x69\x67\x6E\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0A\x47\x6C\x6F\x62\x61\x6C\x53\x69\x67\x6E\x30\x1E\x17\x0D\x30\x36\x31\x32\x31\x35\x30\x38\x30\x30\x30\x30\x5A\x17\x0D\x32\x31\x31\x32\x31\x35\x30\x38\x30\x30\x30\x30\x5A\x30\x4C\x31\x20\x30\x1E\x06\x03\x55\x04\x0B\x13\x17\x47\x6C\x6F\x62\x61\x6C\x53\x69\x67\x6E\x20\x52\x6F\x6F\x74\x20\x43\x41\x20\x2D\x20\x52\x32\x31\x13\x30\x11\x06\x03\x55\x04\x0A\x13\x0A\x47\x6C\x6F\x62\x61\x6C\x53\x69\x67\x6E\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0A\x47\x6C\x6F\x62\x61\x6C\x53\x69\x67\x6E\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xA6\xCF\x24\x0E\xBE\x2E\x6F\x28\x99\x45\x42\xC4\xAB\x3E\x21\x54\x9B\x0B\xD3\x7F\x84\x70\xFA\x12\xB3\xCB\xBF\x87\x5F\xC6\x7F\x86\xD3\xB2\x30\x5C\xD6\xFD\xAD\xF1\x7B\xDC\xE5\xF8\x60\x96\x09\x92\x10\xF5\xD0\x53\xDE\xFB\x7B\x7E\x73\x88\xAC\x52\x88\x7B\x4A\xA6\xCA\x49\xA6\x5E\xA8\xA7\x8C\x5A\x11\xBC\x7A\x82\xEB\xBE\x8C\xE9\xB3\xAC\x96\x25\x07\x97\x4A\x99\x2A\x07\x2F\xB4\x1E\x77\xBF\x8A\x0F\xB5\x02\x7C\x1B\x96\xB8\xC5\xB9\x3A\x2C\xBC\xD6\x12\xB9\xEB\x59\x7D\xE2\xD0\x06\x86\x5F\x5E\x49\x6A\xB5\x39\x5E\x88\x34\xEC\xBC\x78\x0C\x08\x98\x84\x6C\xA8\xCD\x4B\xB4\xA0\x7D\x0C\x79\x4D\xF0\xB8\x2D\xCB\x21\xCA\xD5\x6C\x5B\x7D\xE1\xA0\x29\x84\xA1\xF9\xD3\x94\x49\xCB\x24\x62\x91\x20\xBC\xDD\x0B\xD5\xD9\xCC\xF9\xEA\x27\x0A\x2B\x73\x91\xC6\x9D\x1B\xAC\xC8\xCB\xE8\xE0\xA0\xF4\x2F\x90\x8B\x4D\xFB\xB0\x36\x1B\xF6\x19\x7A\x85\xE0\x6D\xF2\x61\x13\x88\x5C\x9F\xE0\x93\x0A\x51\x97\x8A\x5A\xCE\xAF\xAB\xD5\xF7\xAA\x09\xAA\x60\xBD\xDC\xD9\x5F\xDF\x72\xA9\x60\x13\x5E\x00\x01\xC9\x4A\xFA\x3F\xA4\xEA\x07\x03\x21\x02\x8E\x82\xCA\x03\xC2\x9B\x8F\x02\x03\x01\x00\x01\xA3\x81\x9C\x30\x81\x99\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x9B\xE2\x07\x57\x67\x1C\x1E\xC0\x6A\x06\xDE\x59\xB4\x9A\x2D\xDF\xDC\x19\x86\x2E\x30\x36\x06\x03\x55\x1D\x1F\x04\x2F\x30\x2D\x30\x2B\xA0\x29\xA0\x27\x86\x25\x68\x74\x74\x70\x3A\x2F\x2F\x63\x72\x6C\x2E\x67\x6C\x6F\x62\x61\x6C\x73\x69\x67\x6E\x2E\x6E\x65\x74\x2F\x72\x6F\x6F\x74\x2D\x72\x32\x2E\x63\x72\x6C\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\x9B\xE2\x07\x57\x67\x1C\x1E\xC0\x6A\x06\xDE\x59\xB4\x9A\x2D\xDF\xDC\x19\x86\x2E\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x99\x81\x53\x87\x1C\x68\x97\x86\x91\xEC\xE0\x4A\xB8\x44\x0B\xAB\x81\xAC\x27\x4F\xD6\xC1\xB8\x1C\x43\x78\xB3\x0C\x9A\xFC\xEA\x2C\x3C\x6E\x61\x1B\x4D\x4B\x29\xF5\x9F\x05\x1D\x26\xC1\xB8\xE9\x83\x00\x62\x45\xB6\xA9\x08\x93\xB9\xA9\x33\x4B\x18\x9A\xC2\xF8\x87\x88\x4E\xDB\xDD\x71\x34\x1A\xC1\x54\xDA\x46\x3F\xE0\xD3\x2A\xAB\x6D\x54\x22\xF5\x3A\x62\xCD\x20\x6F\xBA\x29\x89\xD7\xDD\x91\xEE\xD3\x5C\xA2\x3E\xA1\x5B\x41\xF5\xDF\xE5\x64\x43\x2D\xE9\xD5\x39\xAB\xD2\xA2\xDF\xB7\x8B\xD0\xC0\x80\x19\x1C\x45\xC0\x2D\x8C\xE8\xF8\x2D\xA4\x74\x56\x49\xC5\x05\xB5\x4F\x15\xDE\x6E\x44\x78\x39\x87\xA8\x7E\xBB\xF3\x79\x18\x91\xBB\xF4\x6F\x9D\xC1\xF0\x8C\x35\x8C\x5D\x01\xFB\xC3\x6D\xB9\xEF\x44\x6D\x79\x46\x31\x7E\x0A\xFE\xA9\x82\xC1\xFF\xEF\xAB\x6E\x20\xC4\x50\xC9\x5F\x9D\x4D\x9B\x17\x8C\x0C\xE5\x01\xC9\xA0\x41\x6A\x73\x53\xFA\xA5\x50\xB4\x6E\x25\x0F\xFB\x4C\x18\xF4\xFD\x52\xD9\x8E\x69\xB1\xE8\x11\x0F\xDE\x88\xD8\xFB\x1D\x49\xF7\xAA\xDE\x95\xCF\x20\x78\xC2\x60\x12\xDB\x25\x40\x8C\x6A\xFC\x7E\x42\x38\x40\x64\x12\xF7\x9E\x81\xE1\x93\x2E", - ["emailAddress=info@valicert.com,CN=http://www.valicert.com/,OU=ValiCert Class 1 Policy Validation Authority,O=ValiCert\, Inc.,L=ValiCert Validation Network"] = "\x30\x82\x02\xE7\x30\x82\x02\x50\x02\x01\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x81\xBB\x31\x24\x30\x22\x06\x03\x55\x04\x07\x13\x1B\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x4E\x65\x74\x77\x6F\x72\x6B\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x61\x6C\x69\x43\x65\x72\x74\x2C\x20\x49\x6E\x63\x2E\x31\x35\x30\x33\x06\x03\x55\x04\x0B\x13\x2C\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x43\x6C\x61\x73\x73\x20\x31\x20\x50\x6F\x6C\x69\x63\x79\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x31\x21\x30\x1F\x06\x03\x55\x04\x03\x13\x18\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x2F\x31\x20\x30\x1E\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x11\x69\x6E\x66\x6F\x40\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x30\x1E\x17\x0D\x39\x39\x30\x36\x32\x35\x32\x32\x32\x33\x34\x38\x5A\x17\x0D\x31\x39\x30\x36\x32\x35\x32\x32\x32\x33\x34\x38\x5A\x30\x81\xBB\x31\x24\x30\x22\x06\x03\x55\x04\x07\x13\x1B\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x4E\x65\x74\x77\x6F\x72\x6B\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x61\x6C\x69\x43\x65\x72\x74\x2C\x20\x49\x6E\x63\x2E\x31\x35\x30\x33\x06\x03\x55\x04\x0B\x13\x2C\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x43\x6C\x61\x73\x73\x20\x31\x20\x50\x6F\x6C\x69\x63\x79\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x31\x21\x30\x1F\x06\x03\x55\x04\x03\x13\x18\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x2F\x31\x20\x30\x1E\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x11\x69\x6E\x66\x6F\x40\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\xD8\x59\x82\x7A\x89\xB8\x96\xBA\xA6\x2F\x68\x6F\x58\x2E\xA7\x54\x1C\x06\x6E\xF4\xEA\x8D\x48\xBC\x31\x94\x17\xF0\xF3\x4E\xBC\xB2\xB8\x35\x92\x76\xB0\xD0\xA5\xA5\x01\xD7\x00\x03\x12\x22\x19\x08\xF8\xFF\x11\x23\x9B\xCE\x07\xF5\xBF\x69\x1A\x26\xFE\x4E\xE9\xD1\x7F\x9D\x2C\x40\x1D\x59\x68\x6E\xA6\xF8\x58\xB0\x9D\x1A\x8F\xD3\x3F\xF1\xDC\x19\x06\x81\xA8\x0E\xE0\x3A\xDD\xC8\x53\x45\x09\x06\xE6\x0F\x70\xC3\xFA\x40\xA6\x0E\xE2\x56\x05\x0F\x18\x4D\xFC\x20\x82\xD1\x73\x55\x74\x8D\x76\x72\xA0\x1D\x9D\x1D\xC0\xDD\x3F\x71\x02\x03\x01\x00\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x81\x81\x00\x50\x68\x3D\x49\xF4\x2C\x1C\x06\x94\xDF\x95\x60\x7F\x96\x7B\x17\xFE\x4F\x71\xAD\x64\xC8\xDD\x77\xD2\xEF\x59\x55\xE8\x3F\xE8\x8E\x05\x2A\x21\xF2\x07\xD2\xB5\xA7\x52\xFE\x9C\xB1\xB6\xE2\x5B\x77\x17\x40\xEA\x72\xD6\x23\xCB\x28\x81\x32\xC3\x00\x79\x18\xEC\x59\x17\x89\xC9\xC6\x6A\x1E\x71\xC9\xFD\xB7\x74\xA5\x25\x45\x69\xC5\x48\xAB\x19\xE1\x45\x8A\x25\x6B\x19\xEE\xE5\xBB\x12\xF5\x7F\xF7\xA6\x8D\x51\xC3\xF0\x9D\x74\xB7\xA9\x3E\xA0\xA5\xFF\xB6\x49\x03\x13\xDA\x22\xCC\xED\x71\x82\x2B\x99\xCF\x3A\xB7\xF5\x2D\x72\xC8", - ["emailAddress=info@valicert.com,CN=http://www.valicert.com/,OU=ValiCert Class 2 Policy Validation Authority,O=ValiCert\, Inc.,L=ValiCert Validation Network"] = "\x30\x82\x02\xE7\x30\x82\x02\x50\x02\x01\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x81\xBB\x31\x24\x30\x22\x06\x03\x55\x04\x07\x13\x1B\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x4E\x65\x74\x77\x6F\x72\x6B\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x61\x6C\x69\x43\x65\x72\x74\x2C\x20\x49\x6E\x63\x2E\x31\x35\x30\x33\x06\x03\x55\x04\x0B\x13\x2C\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x43\x6C\x61\x73\x73\x20\x32\x20\x50\x6F\x6C\x69\x63\x79\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x31\x21\x30\x1F\x06\x03\x55\x04\x03\x13\x18\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x2F\x31\x20\x30\x1E\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x11\x69\x6E\x66\x6F\x40\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x30\x1E\x17\x0D\x39\x39\x30\x36\x32\x36\x30\x30\x31\x39\x35\x34\x5A\x17\x0D\x31\x39\x30\x36\x32\x36\x30\x30\x31\x39\x35\x34\x5A\x30\x81\xBB\x31\x24\x30\x22\x06\x03\x55\x04\x07\x13\x1B\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x4E\x65\x74\x77\x6F\x72\x6B\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x61\x6C\x69\x43\x65\x72\x74\x2C\x20\x49\x6E\x63\x2E\x31\x35\x30\x33\x06\x03\x55\x04\x0B\x13\x2C\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x43\x6C\x61\x73\x73\x20\x32\x20\x50\x6F\x6C\x69\x63\x79\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x31\x21\x30\x1F\x06\x03\x55\x04\x03\x13\x18\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x2F\x31\x20\x30\x1E\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x11\x69\x6E\x66\x6F\x40\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\xCE\x3A\x71\xCA\xE5\xAB\xC8\x59\x92\x55\xD7\xAB\xD8\x74\x0E\xF9\xEE\xD9\xF6\x55\x47\x59\x65\x47\x0E\x05\x55\xDC\xEB\x98\x36\x3C\x5C\x53\x5D\xD3\x30\xCF\x38\xEC\xBD\x41\x89\xED\x25\x42\x09\x24\x6B\x0A\x5E\xB3\x7C\xDD\x52\x2D\x4C\xE6\xD4\xD6\x7D\x5A\x59\xA9\x65\xD4\x49\x13\x2D\x24\x4D\x1C\x50\x6F\xB5\xC1\x85\x54\x3B\xFE\x71\xE4\xD3\x5C\x42\xF9\x80\xE0\x91\x1A\x0A\x5B\x39\x36\x67\xF3\x3F\x55\x7C\x1B\x3F\xB4\x5F\x64\x73\x34\xE3\xB4\x12\xBF\x87\x64\xF8\xDA\x12\xFF\x37\x27\xC1\xB3\x43\xBB\xEF\x7B\x6E\x2E\x69\xF7\x02\x03\x01\x00\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x81\x81\x00\x3B\x7F\x50\x6F\x6F\x50\x94\x99\x49\x62\x38\x38\x1F\x4B\xF8\xA5\xC8\x3E\xA7\x82\x81\xF6\x2B\xC7\xE8\xC5\xCE\xE8\x3A\x10\x82\xCB\x18\x00\x8E\x4D\xBD\xA8\x58\x7F\xA1\x79\x00\xB5\xBB\xE9\x8D\xAF\x41\xD9\x0F\x34\xEE\x21\x81\x19\xA0\x32\x49\x28\xF4\xC4\x8E\x56\xD5\x52\x33\xFD\x50\xD5\x7E\x99\x6C\x03\xE4\xC9\x4C\xFC\xCB\x6C\xAB\x66\xB3\x4A\x21\x8C\xE5\xB5\x0C\x32\x3E\x10\xB2\xCC\x6C\xA1\xDC\x9A\x98\x4C\x02\x5B\xF3\xCE\xB9\x9E\xA5\x72\x0E\x4A\xB7\x3F\x3C\xE6\x16\x68\xF8\xBE\xED\x74\x4C\xBC\x5B\xD5\x62\x1F\x43\xDD", - ["emailAddress=info@valicert.com,CN=http://www.valicert.com/,OU=ValiCert Class 3 Policy Validation Authority,O=ValiCert\, Inc.,L=ValiCert Validation Network"] = "\x30\x82\x02\xE7\x30\x82\x02\x50\x02\x01\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x81\xBB\x31\x24\x30\x22\x06\x03\x55\x04\x07\x13\x1B\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x4E\x65\x74\x77\x6F\x72\x6B\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x61\x6C\x69\x43\x65\x72\x74\x2C\x20\x49\x6E\x63\x2E\x31\x35\x30\x33\x06\x03\x55\x04\x0B\x13\x2C\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x43\x6C\x61\x73\x73\x20\x33\x20\x50\x6F\x6C\x69\x63\x79\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x31\x21\x30\x1F\x06\x03\x55\x04\x03\x13\x18\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x2F\x31\x20\x30\x1E\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x11\x69\x6E\x66\x6F\x40\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x30\x1E\x17\x0D\x39\x39\x30\x36\x32\x36\x30\x30\x32\x32\x33\x33\x5A\x17\x0D\x31\x39\x30\x36\x32\x36\x30\x30\x32\x32\x33\x33\x5A\x30\x81\xBB\x31\x24\x30\x22\x06\x03\x55\x04\x07\x13\x1B\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x4E\x65\x74\x77\x6F\x72\x6B\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x61\x6C\x69\x43\x65\x72\x74\x2C\x20\x49\x6E\x63\x2E\x31\x35\x30\x33\x06\x03\x55\x04\x0B\x13\x2C\x56\x61\x6C\x69\x43\x65\x72\x74\x20\x43\x6C\x61\x73\x73\x20\x33\x20\x50\x6F\x6C\x69\x63\x79\x20\x56\x61\x6C\x69\x64\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x31\x21\x30\x1F\x06\x03\x55\x04\x03\x13\x18\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x2F\x31\x20\x30\x1E\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x11\x69\x6E\x66\x6F\x40\x76\x61\x6C\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\xE3\x98\x51\x96\x1C\xE8\xD5\xB1\x06\x81\x6A\x57\xC3\x72\x75\x93\xAB\xCF\x9E\xA6\xFC\xF3\x16\x52\xD6\x2D\x4D\x9F\x35\x44\xA8\x2E\x04\x4D\x07\x49\x8A\x38\x29\xF5\x77\x37\xE7\xB7\xAB\x5D\xDF\x36\x71\x14\x99\x8F\xDC\xC2\x92\xF1\xE7\x60\x92\x97\xEC\xD8\x48\xDC\xBF\xC1\x02\x20\xC6\x24\xA4\x28\x4C\x30\x5A\x76\x6D\xB1\x5C\xF3\xDD\xDE\x9E\x10\x71\xA1\x88\xC7\x5B\x9B\x41\x6D\xCA\xB0\xB8\x8E\x15\xEE\xAD\x33\x2B\xCF\x47\x04\x5C\x75\x71\x0A\x98\x24\x98\x29\xA7\x49\x59\xA5\xDD\xF8\xB7\x43\x62\x61\xF3\xD3\xE2\xD0\x55\x3F\x02\x03\x01\x00\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x81\x81\x00\x56\xBB\x02\x58\x84\x67\x08\x2C\xDF\x1F\xDB\x7B\x49\x33\xF5\xD3\x67\x9D\xF4\xB4\x0A\x10\xB3\xC9\xC5\x2C\xE2\x92\x6A\x71\x78\x27\xF2\x70\x83\x42\xD3\x3E\xCF\xA9\x54\xF4\xF1\xD8\x92\x16\x8C\xD1\x04\xCB\x4B\xAB\xC9\x9F\x45\xAE\x3C\x8A\xA9\xB0\x71\x33\x5D\xC8\xC5\x57\xDF\xAF\xA8\x35\xB3\x7F\x89\x87\xE9\xE8\x25\x92\xB8\x7F\x85\x7A\xAE\xD6\xBC\x1E\x37\x58\x2A\x67\xC9\x91\xCF\x2A\x81\x3E\xED\xC6\x39\xDF\xC0\x3E\x19\x9C\x19\xCC\x13\x4D\x82\x41\xB5\x8C\xDE\xE0\x3D\x60\x08\x20\x0F\x45\x7E\x6B\xA2\x7F\xA3\x8C\x15\xEE", ["CN=VeriSign Class 3 Public Primary Certification Authority - G3,OU=(c) 1999 VeriSign\, Inc. - For authorized use only,OU=VeriSign Trust Network,O=VeriSign\, Inc.,C=US"] = "\x30\x82\x04\x1A\x30\x82\x03\x02\x02\x11\x00\x9B\x7E\x06\x49\xA3\x3E\x62\xB9\xD5\xEE\x90\x48\x71\x29\xEF\x57\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x81\xCA\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x31\x1F\x30\x1D\x06\x03\x55\x04\x0B\x13\x16\x56\x65\x72\x69\x53\x69\x67\x6E\x20\x54\x72\x75\x73\x74\x20\x4E\x65\x74\x77\x6F\x72\x6B\x31\x3A\x30\x38\x06\x03\x55\x04\x0B\x13\x31\x28\x63\x29\x20\x31\x39\x39\x39\x20\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x20\x2D\x20\x46\x6F\x72\x20\x61\x75\x74\x68\x6F\x72\x69\x7A\x65\x64\x20\x75\x73\x65\x20\x6F\x6E\x6C\x79\x31\x45\x30\x43\x06\x03\x55\x04\x03\x13\x3C\x56\x65\x72\x69\x53\x69\x67\x6E\x20\x43\x6C\x61\x73\x73\x20\x33\x20\x50\x75\x62\x6C\x69\x63\x20\x50\x72\x69\x6D\x61\x72\x79\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x20\x2D\x20\x47\x33\x30\x1E\x17\x0D\x39\x39\x31\x30\x30\x31\x30\x30\x30\x30\x30\x30\x5A\x17\x0D\x33\x36\x30\x37\x31\x36\x32\x33\x35\x39\x35\x39\x5A\x30\x81\xCA\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x31\x1F\x30\x1D\x06\x03\x55\x04\x0B\x13\x16\x56\x65\x72\x69\x53\x69\x67\x6E\x20\x54\x72\x75\x73\x74\x20\x4E\x65\x74\x77\x6F\x72\x6B\x31\x3A\x30\x38\x06\x03\x55\x04\x0B\x13\x31\x28\x63\x29\x20\x31\x39\x39\x39\x20\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x20\x2D\x20\x46\x6F\x72\x20\x61\x75\x74\x68\x6F\x72\x69\x7A\x65\x64\x20\x75\x73\x65\x20\x6F\x6E\x6C\x79\x31\x45\x30\x43\x06\x03\x55\x04\x03\x13\x3C\x56\x65\x72\x69\x53\x69\x67\x6E\x20\x43\x6C\x61\x73\x73\x20\x33\x20\x50\x75\x62\x6C\x69\x63\x20\x50\x72\x69\x6D\x61\x72\x79\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x20\x2D\x20\x47\x33\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xCB\xBA\x9C\x52\xFC\x78\x1F\x1A\x1E\x6F\x1B\x37\x73\xBD\xF8\xC9\x6B\x94\x12\x30\x4F\xF0\x36\x47\xF5\xD0\x91\x0A\xF5\x17\xC8\xA5\x61\xC1\x16\x40\x4D\xFB\x8A\x61\x90\xE5\x76\x20\xC1\x11\x06\x7D\xAB\x2C\x6E\xA6\xF5\x11\x41\x8E\xFA\x2D\xAD\x2A\x61\x59\xA4\x67\x26\x4C\xD0\xE8\xBC\x52\x5B\x70\x20\x04\x58\xD1\x7A\xC9\xA4\x69\xBC\x83\x17\x64\xAD\x05\x8B\xBC\xD0\x58\xCE\x8D\x8C\xF5\xEB\xF0\x42\x49\x0B\x9D\x97\x27\x67\x32\x6E\xE1\xAE\x93\x15\x1C\x70\xBC\x20\x4D\x2F\x18\xDE\x92\x88\xE8\x6C\x85\x57\x11\x1A\xE9\x7E\xE3\x26\x11\x54\xA2\x45\x96\x55\x83\xCA\x30\x89\xE8\xDC\xD8\xA3\xED\x2A\x80\x3F\x7F\x79\x65\x57\x3E\x15\x20\x66\x08\x2F\x95\x93\xBF\xAA\x47\x2F\xA8\x46\x97\xF0\x12\xE2\xFE\xC2\x0A\x2B\x51\xE6\x76\xE6\xB7\x46\xB7\xE2\x0D\xA6\xCC\xA8\xC3\x4C\x59\x55\x89\xE6\xE8\x53\x5C\x1C\xEA\x9D\xF0\x62\x16\x0B\xA7\xC9\x5F\x0C\xF0\xDE\xC2\x76\xCE\xAF\xF7\x6A\xF2\xFA\x41\xA6\xA2\x33\x14\xC9\xE5\x7A\x63\xD3\x9E\x62\x37\xD5\x85\x65\x9E\x0E\xE6\x53\x24\x74\x1B\x5E\x1D\x12\x53\x5B\xC7\x2C\xE7\x83\x49\x3B\x15\xAE\x8A\x68\xB9\x57\x97\x02\x03\x01\x00\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x11\x14\x96\xC1\xAB\x92\x08\xF7\x3F\x2F\xC9\xB2\xFE\xE4\x5A\x9F\x64\xDE\xDB\x21\x4F\x86\x99\x34\x76\x36\x57\xDD\xD0\x15\x2F\xC5\xAD\x7F\x15\x1F\x37\x62\x73\x3E\xD4\xE7\x5F\xCE\x17\x03\xDB\x35\xFA\x2B\xDB\xAE\x60\x09\x5F\x1E\x5F\x8F\x6E\xBB\x0B\x3D\xEA\x5A\x13\x1E\x0C\x60\x6F\xB5\xC0\xB5\x23\x22\x2E\x07\x0B\xCB\xA9\x74\xCB\x47\xBB\x1D\xC1\xD7\xA5\x6B\xCC\x2F\xD2\x42\xFD\x49\xDD\xA7\x89\xCF\x53\xBA\xDA\x00\x5A\x28\xBF\x82\xDF\xF8\xBA\x13\x1D\x50\x86\x82\xFD\x8E\x30\x8F\x29\x46\xB0\x1E\x3D\x35\xDA\x38\x62\x16\x18\x4A\xAD\xE6\xB6\x51\x6C\xDE\xAF\x62\xEB\x01\xD0\x1E\x24\xFE\x7A\x8F\x12\x1A\x12\x68\xB8\xFB\x66\x99\x14\x14\x45\x5C\xAE\xE7\xAE\x69\x17\x81\x2B\x5A\x37\xC9\x5E\x2A\xF4\xC6\xE2\xA1\x5C\x54\x9B\xA6\x54\x00\xCF\xF0\xF1\xC1\xC7\x98\x30\x1A\x3B\x36\x16\xDB\xA3\x6E\xEA\xFD\xAD\xB2\xC2\xDA\xEF\x02\x47\x13\x8A\xC0\xF1\xB3\x31\xAD\x4F\x1C\xE1\x4F\x9C\xAF\x0F\x0C\x9D\xF7\x78\x0D\xD8\xF4\x35\x56\x80\xDA\xB7\x6D\x17\x8F\x9D\x1E\x81\x64\xE1\xFE\xC5\x45\xBA\xAD\x6B\xB9\x0A\x7A\x4E\x4F\x4B\x84\xEE\x4B\xF1\x7D\xDD\x11", ["CN=VeriSign Class 4 Public Primary Certification Authority - G3,OU=(c) 1999 VeriSign\, Inc. - For authorized use only,OU=VeriSign Trust Network,O=VeriSign\, Inc.,C=US"] = "\x30\x82\x04\x1A\x30\x82\x03\x02\x02\x11\x00\xEC\xA0\xA7\x8B\x6E\x75\x6A\x01\xCF\xC4\x7C\xCC\x2F\x94\x5E\xD7\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x81\xCA\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x31\x1F\x30\x1D\x06\x03\x55\x04\x0B\x13\x16\x56\x65\x72\x69\x53\x69\x67\x6E\x20\x54\x72\x75\x73\x74\x20\x4E\x65\x74\x77\x6F\x72\x6B\x31\x3A\x30\x38\x06\x03\x55\x04\x0B\x13\x31\x28\x63\x29\x20\x31\x39\x39\x39\x20\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x20\x2D\x20\x46\x6F\x72\x20\x61\x75\x74\x68\x6F\x72\x69\x7A\x65\x64\x20\x75\x73\x65\x20\x6F\x6E\x6C\x79\x31\x45\x30\x43\x06\x03\x55\x04\x03\x13\x3C\x56\x65\x72\x69\x53\x69\x67\x6E\x20\x43\x6C\x61\x73\x73\x20\x34\x20\x50\x75\x62\x6C\x69\x63\x20\x50\x72\x69\x6D\x61\x72\x79\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x20\x2D\x20\x47\x33\x30\x1E\x17\x0D\x39\x39\x31\x30\x30\x31\x30\x30\x30\x30\x30\x30\x5A\x17\x0D\x33\x36\x30\x37\x31\x36\x32\x33\x35\x39\x35\x39\x5A\x30\x81\xCA\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x31\x1F\x30\x1D\x06\x03\x55\x04\x0B\x13\x16\x56\x65\x72\x69\x53\x69\x67\x6E\x20\x54\x72\x75\x73\x74\x20\x4E\x65\x74\x77\x6F\x72\x6B\x31\x3A\x30\x38\x06\x03\x55\x04\x0B\x13\x31\x28\x63\x29\x20\x31\x39\x39\x39\x20\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x20\x2D\x20\x46\x6F\x72\x20\x61\x75\x74\x68\x6F\x72\x69\x7A\x65\x64\x20\x75\x73\x65\x20\x6F\x6E\x6C\x79\x31\x45\x30\x43\x06\x03\x55\x04\x03\x13\x3C\x56\x65\x72\x69\x53\x69\x67\x6E\x20\x43\x6C\x61\x73\x73\x20\x34\x20\x50\x75\x62\x6C\x69\x63\x20\x50\x72\x69\x6D\x61\x72\x79\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x20\x2D\x20\x47\x33\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xAD\xCB\xA5\x11\x69\xC6\x59\xAB\xF1\x8F\xB5\x19\x0F\x56\xCE\xCC\xB5\x1F\x20\xE4\x9E\x26\x25\x4B\xE0\x73\x65\x89\x59\xDE\xD0\x83\xE4\xF5\x0F\xB5\xBB\xAD\xF1\x7C\xE8\x21\xFC\xE4\xE8\x0C\xEE\x7C\x45\x22\x19\x76\x92\xB4\x13\xB7\x20\x5B\x09\xFA\x61\xAE\xA8\xF2\xA5\x8D\x85\xC2\x2A\xD6\xDE\x66\x36\xD2\x9B\x02\xF4\xA8\x92\x60\x7C\x9C\x69\xB4\x8F\x24\x1E\xD0\x86\x52\xF6\x32\x9C\x41\x58\x1E\x22\xBD\xCD\x45\x62\x95\x08\x6E\xD0\x66\xDD\x53\xA2\xCC\xF0\x10\xDC\x54\x73\x8B\x04\xA1\x46\x33\x33\x5C\x17\x40\xB9\x9E\x4D\xD3\xF3\xBE\x55\x83\xE8\xB1\x89\x8E\x5A\x7C\x9A\x96\x22\x90\x3B\x88\x25\xF2\xD2\x53\x88\x02\x0C\x0B\x78\xF2\xE6\x37\x17\x4B\x30\x46\x07\xE4\x80\x6D\xA6\xD8\x96\x2E\xE8\x2C\xF8\x11\xB3\x38\x0D\x66\xA6\x9B\xEA\xC9\x23\x5B\xDB\x8E\xE2\xF3\x13\x8E\x1A\x59\x2D\xAA\x02\xF0\xEC\xA4\x87\x66\xDC\xC1\x3F\xF5\xD8\xB9\xF4\xEC\x82\xC6\xD2\x3D\x95\x1D\xE5\xC0\x4F\x84\xC9\xD9\xA3\x44\x28\x06\x6A\xD7\x45\xAC\xF0\x6B\x6A\xEF\x4E\x5F\xF8\x11\x82\x1E\x38\x63\x34\x66\x50\xD4\x3E\x93\x73\xFA\x30\xC3\x66\xAD\xFF\x93\x2D\x97\xEF\x03\x02\x03\x01\x00\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x8F\xFA\x25\x6B\x4F\x5B\xE4\xA4\x4E\x27\x55\xAB\x22\x15\x59\x3C\xCA\xB5\x0A\xD4\x4A\xDB\xAB\xDD\xA1\x5F\x53\xC5\xA0\x57\x39\xC2\xCE\x47\x2B\xBE\x3A\xC8\x56\xBF\xC2\xD9\x27\x10\x3A\xB1\x05\x3C\xC0\x77\x31\xBB\x3A\xD3\x05\x7B\x6D\x9A\x1C\x30\x8C\x80\xCB\x93\x93\x2A\x83\xAB\x05\x51\x82\x02\x00\x11\x67\x6B\xF3\x88\x61\x47\x5F\x03\x93\xD5\x5B\x0D\xE0\xF1\xD4\xA1\x32\x35\x85\xB2\x3A\xDB\xB0\x82\xAB\xD1\xCB\x0A\xBC\x4F\x8C\x5B\xC5\x4B\x00\x3B\x1F\x2A\x82\xA6\x7E\x36\x85\xDC\x7E\x3C\x67\x00\xB5\xE4\x3B\x52\xE0\xA8\xEB\x5D\x15\xF9\xC6\x6D\xF0\xAD\x1D\x0E\x85\xB7\xA9\x9A\x73\x14\x5A\x5B\x8F\x41\x28\xC0\xD5\xE8\x2D\x4D\xA4\x5E\xCD\xAA\xD9\xED\xCE\xDC\xD8\xD5\x3C\x42\x1D\x17\xC1\x12\x5D\x45\x38\xC3\x38\xF3\xFC\x85\x2E\x83\x46\x48\xB2\xD7\x20\x5F\x92\x36\x8F\xE7\x79\x0F\x98\x5E\x99\xE8\xF0\xD0\xA4\xBB\xF5\x53\xBD\x2A\xCE\x59\xB0\xAF\x6E\x7F\x6C\xBB\xD2\x1E\x00\xB0\x21\xED\xF8\x41\x62\x82\xB9\xD8\xB2\xC4\xBB\x46\x50\xF3\x31\xC5\x8F\x01\xA8\x74\xEB\xF5\x78\x27\xDA\xE7\xF7\x66\x43\xF3\x9E\x83\x3E\x20\xAA\xC3\x35\x60\x91\xCE", - ["CN=Entrust.net Secure Server Certification Authority,OU=(c) 1999 Entrust.net Limited,OU=www.entrust.net/CPS incorp. by ref. (limits liab.),O=Entrust.net,C=US"] = "\x30\x82\x04\xD8\x30\x82\x04\x41\xA0\x03\x02\x01\x02\x02\x04\x37\x4A\xD2\x43\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x81\xC3\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x14\x30\x12\x06\x03\x55\x04\x0A\x13\x0B\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x31\x3B\x30\x39\x06\x03\x55\x04\x0B\x13\x32\x77\x77\x77\x2E\x65\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x2F\x43\x50\x53\x20\x69\x6E\x63\x6F\x72\x70\x2E\x20\x62\x79\x20\x72\x65\x66\x2E\x20\x28\x6C\x69\x6D\x69\x74\x73\x20\x6C\x69\x61\x62\x2E\x29\x31\x25\x30\x23\x06\x03\x55\x04\x0B\x13\x1C\x28\x63\x29\x20\x31\x39\x39\x39\x20\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x20\x4C\x69\x6D\x69\x74\x65\x64\x31\x3A\x30\x38\x06\x03\x55\x04\x03\x13\x31\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x20\x53\x65\x63\x75\x72\x65\x20\x53\x65\x72\x76\x65\x72\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x1E\x17\x0D\x39\x39\x30\x35\x32\x35\x31\x36\x30\x39\x34\x30\x5A\x17\x0D\x31\x39\x30\x35\x32\x35\x31\x36\x33\x39\x34\x30\x5A\x30\x81\xC3\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x14\x30\x12\x06\x03\x55\x04\x0A\x13\x0B\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x31\x3B\x30\x39\x06\x03\x55\x04\x0B\x13\x32\x77\x77\x77\x2E\x65\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x2F\x43\x50\x53\x20\x69\x6E\x63\x6F\x72\x70\x2E\x20\x62\x79\x20\x72\x65\x66\x2E\x20\x28\x6C\x69\x6D\x69\x74\x73\x20\x6C\x69\x61\x62\x2E\x29\x31\x25\x30\x23\x06\x03\x55\x04\x0B\x13\x1C\x28\x63\x29\x20\x31\x39\x39\x39\x20\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x20\x4C\x69\x6D\x69\x74\x65\x64\x31\x3A\x30\x38\x06\x03\x55\x04\x03\x13\x31\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x20\x53\x65\x63\x75\x72\x65\x20\x53\x65\x72\x76\x65\x72\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x81\x9D\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8B\x00\x30\x81\x87\x02\x81\x81\x00\xCD\x28\x83\x34\x54\x1B\x89\xF3\x0F\xAF\x37\x91\x31\xFF\xAF\x31\x60\xC9\xA8\xE8\xB2\x10\x68\xED\x9F\xE7\x93\x36\xF1\x0A\x64\xBB\x47\xF5\x04\x17\x3F\x23\x47\x4D\xC5\x27\x19\x81\x26\x0C\x54\x72\x0D\x88\x2D\xD9\x1F\x9A\x12\x9F\xBC\xB3\x71\xD3\x80\x19\x3F\x47\x66\x7B\x8C\x35\x28\xD2\xB9\x0A\xDF\x24\xDA\x9C\xD6\x50\x79\x81\x7A\x5A\xD3\x37\xF7\xC2\x4A\xD8\x29\x92\x26\x64\xD1\xE4\x98\x6C\x3A\x00\x8A\xF5\x34\x9B\x65\xF8\xED\xE3\x10\xFF\xFD\xB8\x49\x58\xDC\xA0\xDE\x82\x39\x6B\x81\xB1\x16\x19\x61\xB9\x54\xB6\xE6\x43\x02\x01\x03\xA3\x82\x01\xD7\x30\x82\x01\xD3\x30\x11\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x01\x04\x04\x03\x02\x00\x07\x30\x82\x01\x19\x06\x03\x55\x1D\x1F\x04\x82\x01\x10\x30\x82\x01\x0C\x30\x81\xDE\xA0\x81\xDB\xA0\x81\xD8\xA4\x81\xD5\x30\x81\xD2\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x14\x30\x12\x06\x03\x55\x04\x0A\x13\x0B\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x31\x3B\x30\x39\x06\x03\x55\x04\x0B\x13\x32\x77\x77\x77\x2E\x65\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x2F\x43\x50\x53\x20\x69\x6E\x63\x6F\x72\x70\x2E\x20\x62\x79\x20\x72\x65\x66\x2E\x20\x28\x6C\x69\x6D\x69\x74\x73\x20\x6C\x69\x61\x62\x2E\x29\x31\x25\x30\x23\x06\x03\x55\x04\x0B\x13\x1C\x28\x63\x29\x20\x31\x39\x39\x39\x20\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x20\x4C\x69\x6D\x69\x74\x65\x64\x31\x3A\x30\x38\x06\x03\x55\x04\x03\x13\x31\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x20\x53\x65\x63\x75\x72\x65\x20\x53\x65\x72\x76\x65\x72\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x31\x0D\x30\x0B\x06\x03\x55\x04\x03\x13\x04\x43\x52\x4C\x31\x30\x29\xA0\x27\xA0\x25\x86\x23\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x65\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x2F\x43\x52\x4C\x2F\x6E\x65\x74\x31\x2E\x63\x72\x6C\x30\x2B\x06\x03\x55\x1D\x10\x04\x24\x30\x22\x80\x0F\x31\x39\x39\x39\x30\x35\x32\x35\x31\x36\x30\x39\x34\x30\x5A\x81\x0F\x32\x30\x31\x39\x30\x35\x32\x35\x31\x36\x30\x39\x34\x30\x5A\x30\x0B\x06\x03\x55\x1D\x0F\x04\x04\x03\x02\x01\x06\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\xF0\x17\x62\x13\x55\x3D\xB3\xFF\x0A\x00\x6B\xFB\x50\x84\x97\xF3\xED\x62\xD0\x1A\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xF0\x17\x62\x13\x55\x3D\xB3\xFF\x0A\x00\x6B\xFB\x50\x84\x97\xF3\xED\x62\xD0\x1A\x30\x0C\x06\x03\x55\x1D\x13\x04\x05\x30\x03\x01\x01\xFF\x30\x19\x06\x09\x2A\x86\x48\x86\xF6\x7D\x07\x41\x00\x04\x0C\x30\x0A\x1B\x04\x56\x34\x2E\x30\x03\x02\x04\x90\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x81\x81\x00\x90\xDC\x30\x02\xFA\x64\x74\xC2\xA7\x0A\xA5\x7C\x21\x8D\x34\x17\xA8\xFB\x47\x0E\xFF\x25\x7C\x8D\x13\x0A\xFB\xE4\x98\xB5\xEF\x8C\xF8\xC5\x10\x0D\xF7\x92\xBE\xF1\xC3\xD5\xD5\x95\x6A\x04\xBB\x2C\xCE\x26\x36\x65\xC8\x31\xC6\xE7\xEE\x3F\xE3\x57\x75\x84\x7A\x11\xEF\x46\x4F\x18\xF4\xD3\x98\xBB\xA8\x87\x32\xBA\x72\xF6\x3C\xE2\x3D\x9F\xD7\x1D\xD9\xC3\x60\x43\x8C\x58\x0E\x22\x96\x2F\x62\xA3\x2C\x1F\xBA\xAD\x05\xEF\xAB\x32\x78\x87\xA0\x54\x73\x19\xB5\x5C\x05\xF9\x52\x3E\x6D\x2D\x45\x0B\xF7\x0A\x93\xEA\xED\x06\xF9\xB2", ["CN=Entrust.net Certification Authority (2048),OU=(c) 1999 Entrust.net Limited,OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.),O=Entrust.net"] = "\x30\x82\x04\x2A\x30\x82\x03\x12\xA0\x03\x02\x01\x02\x02\x04\x38\x63\xDE\xF8\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x81\xB4\x31\x14\x30\x12\x06\x03\x55\x04\x0A\x13\x0B\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x31\x40\x30\x3E\x06\x03\x55\x04\x0B\x14\x37\x77\x77\x77\x2E\x65\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x2F\x43\x50\x53\x5F\x32\x30\x34\x38\x20\x69\x6E\x63\x6F\x72\x70\x2E\x20\x62\x79\x20\x72\x65\x66\x2E\x20\x28\x6C\x69\x6D\x69\x74\x73\x20\x6C\x69\x61\x62\x2E\x29\x31\x25\x30\x23\x06\x03\x55\x04\x0B\x13\x1C\x28\x63\x29\x20\x31\x39\x39\x39\x20\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x20\x4C\x69\x6D\x69\x74\x65\x64\x31\x33\x30\x31\x06\x03\x55\x04\x03\x13\x2A\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x20\x28\x32\x30\x34\x38\x29\x30\x1E\x17\x0D\x39\x39\x31\x32\x32\x34\x31\x37\x35\x30\x35\x31\x5A\x17\x0D\x32\x39\x30\x37\x32\x34\x31\x34\x31\x35\x31\x32\x5A\x30\x81\xB4\x31\x14\x30\x12\x06\x03\x55\x04\x0A\x13\x0B\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x31\x40\x30\x3E\x06\x03\x55\x04\x0B\x14\x37\x77\x77\x77\x2E\x65\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x2F\x43\x50\x53\x5F\x32\x30\x34\x38\x20\x69\x6E\x63\x6F\x72\x70\x2E\x20\x62\x79\x20\x72\x65\x66\x2E\x20\x28\x6C\x69\x6D\x69\x74\x73\x20\x6C\x69\x61\x62\x2E\x29\x31\x25\x30\x23\x06\x03\x55\x04\x0B\x13\x1C\x28\x63\x29\x20\x31\x39\x39\x39\x20\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x20\x4C\x69\x6D\x69\x74\x65\x64\x31\x33\x30\x31\x06\x03\x55\x04\x03\x13\x2A\x45\x6E\x74\x72\x75\x73\x74\x2E\x6E\x65\x74\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x20\x28\x32\x30\x34\x38\x29\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xAD\x4D\x4B\xA9\x12\x86\xB2\xEA\xA3\x20\x07\x15\x16\x64\x2A\x2B\x4B\xD1\xBF\x0B\x4A\x4D\x8E\xED\x80\x76\xA5\x67\xB7\x78\x40\xC0\x73\x42\xC8\x68\xC0\xDB\x53\x2B\xDD\x5E\xB8\x76\x98\x35\x93\x8B\x1A\x9D\x7C\x13\x3A\x0E\x1F\x5B\xB7\x1E\xCF\xE5\x24\x14\x1E\xB1\x81\xA9\x8D\x7D\xB8\xCC\x6B\x4B\x03\xF1\x02\x0C\xDC\xAB\xA5\x40\x24\x00\x7F\x74\x94\xA1\x9D\x08\x29\xB3\x88\x0B\xF5\x87\x77\x9D\x55\xCD\xE4\xC3\x7E\xD7\x6A\x64\xAB\x85\x14\x86\x95\x5B\x97\x32\x50\x6F\x3D\xC8\xBA\x66\x0C\xE3\xFC\xBD\xB8\x49\xC1\x76\x89\x49\x19\xFD\xC0\xA8\xBD\x89\xA3\x67\x2F\xC6\x9F\xBC\x71\x19\x60\xB8\x2D\xE9\x2C\xC9\x90\x76\x66\x7B\x94\xE2\xAF\x78\xD6\x65\x53\x5D\x3C\xD6\x9C\xB2\xCF\x29\x03\xF9\x2F\xA4\x50\xB2\xD4\x48\xCE\x05\x32\x55\x8A\xFD\xB2\x64\x4C\x0E\xE4\x98\x07\x75\xDB\x7F\xDF\xB9\x08\x55\x60\x85\x30\x29\xF9\x7B\x48\xA4\x69\x86\xE3\x35\x3F\x1E\x86\x5D\x7A\x7A\x15\xBD\xEF\x00\x8E\x15\x22\x54\x17\x00\x90\x26\x93\xBC\x0E\x49\x68\x91\xBF\xF8\x47\xD3\x9D\x95\x42\xC1\x0E\x4D\xDF\x6F\x26\xCF\xC3\x18\x21\x62\x66\x43\x70\xD6\xD5\xC0\x07\xE1\x02\x03\x01\x00\x01\xA3\x42\x30\x40\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x55\xE4\x81\xD1\x11\x80\xBE\xD8\x89\xB9\x08\xA3\x31\xF9\xA1\x24\x09\x16\xB9\x70\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x3B\x9B\x8F\x56\x9B\x30\xE7\x53\x99\x7C\x7A\x79\xA7\x4D\x97\xD7\x19\x95\x90\xFB\x06\x1F\xCA\x33\x7C\x46\x63\x8F\x96\x66\x24\xFA\x40\x1B\x21\x27\xCA\xE6\x72\x73\xF2\x4F\xFE\x31\x99\xFD\xC8\x0C\x4C\x68\x53\xC6\x80\x82\x13\x98\xFA\xB6\xAD\xDA\x5D\x3D\xF1\xCE\x6E\xF6\x15\x11\x94\x82\x0C\xEE\x3F\x95\xAF\x11\xAB\x0F\xD7\x2F\xDE\x1F\x03\x8F\x57\x2C\x1E\xC9\xBB\x9A\x1A\x44\x95\xEB\x18\x4F\xA6\x1F\xCD\x7D\x57\x10\x2F\x9B\x04\x09\x5A\x84\xB5\x6E\xD8\x1D\x3A\xE1\xD6\x9E\xD1\x6C\x79\x5E\x79\x1C\x14\xC5\xE3\xD0\x4C\x93\x3B\x65\x3C\xED\xDF\x3D\xBE\xA6\xE5\x95\x1A\xC3\xB5\x19\xC3\xBD\x5E\x5B\xBB\xFF\x23\xEF\x68\x19\xCB\x12\x93\x27\x5C\x03\x2D\x6F\x30\xD0\x1E\xB6\x1A\xAC\xDE\x5A\xF7\xD1\xAA\xA8\x27\xA6\xFE\x79\x81\xC4\x79\x99\x33\x57\xBA\x12\xB0\xA9\xE0\x42\x6C\x93\xCA\x56\xDE\xFE\x6D\x84\x0B\x08\x8B\x7E\x8D\xEA\xD7\x98\x21\xC6\xF3\xE7\x3C\x79\x2F\x5E\x9C\xD1\x4C\x15\x8D\xE1\xEC\x22\x37\xCC\x9A\x43\x0B\x97\xDC\x80\x90\x8D\xB3\x67\x9B\x6F\x48\x08\x15\x56\xCF\xBF\xF1\x2B\x7C\x5E\x9A\x76\xE9\x59\x90\xC5\x7C\x83\x35\x11\x65\x51", ["CN=Baltimore CyberTrust Root,OU=CyberTrust,O=Baltimore,C=IE"] = "\x30\x82\x03\x77\x30\x82\x02\x5F\xA0\x03\x02\x01\x02\x02\x04\x02\x00\x00\xB9\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x5A\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x49\x45\x31\x12\x30\x10\x06\x03\x55\x04\x0A\x13\x09\x42\x61\x6C\x74\x69\x6D\x6F\x72\x65\x31\x13\x30\x11\x06\x03\x55\x04\x0B\x13\x0A\x43\x79\x62\x65\x72\x54\x72\x75\x73\x74\x31\x22\x30\x20\x06\x03\x55\x04\x03\x13\x19\x42\x61\x6C\x74\x69\x6D\x6F\x72\x65\x20\x43\x79\x62\x65\x72\x54\x72\x75\x73\x74\x20\x52\x6F\x6F\x74\x30\x1E\x17\x0D\x30\x30\x30\x35\x31\x32\x31\x38\x34\x36\x30\x30\x5A\x17\x0D\x32\x35\x30\x35\x31\x32\x32\x33\x35\x39\x30\x30\x5A\x30\x5A\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x49\x45\x31\x12\x30\x10\x06\x03\x55\x04\x0A\x13\x09\x42\x61\x6C\x74\x69\x6D\x6F\x72\x65\x31\x13\x30\x11\x06\x03\x55\x04\x0B\x13\x0A\x43\x79\x62\x65\x72\x54\x72\x75\x73\x74\x31\x22\x30\x20\x06\x03\x55\x04\x03\x13\x19\x42\x61\x6C\x74\x69\x6D\x6F\x72\x65\x20\x43\x79\x62\x65\x72\x54\x72\x75\x73\x74\x20\x52\x6F\x6F\x74\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xA3\x04\xBB\x22\xAB\x98\x3D\x57\xE8\x26\x72\x9A\xB5\x79\xD4\x29\xE2\xE1\xE8\x95\x80\xB1\xB0\xE3\x5B\x8E\x2B\x29\x9A\x64\xDF\xA1\x5D\xED\xB0\x09\x05\x6D\xDB\x28\x2E\xCE\x62\xA2\x62\xFE\xB4\x88\xDA\x12\xEB\x38\xEB\x21\x9D\xC0\x41\x2B\x01\x52\x7B\x88\x77\xD3\x1C\x8F\xC7\xBA\xB9\x88\xB5\x6A\x09\xE7\x73\xE8\x11\x40\xA7\xD1\xCC\xCA\x62\x8D\x2D\xE5\x8F\x0B\xA6\x50\xD2\xA8\x50\xC3\x28\xEA\xF5\xAB\x25\x87\x8A\x9A\x96\x1C\xA9\x67\xB8\x3F\x0C\xD5\xF7\xF9\x52\x13\x2F\xC2\x1B\xD5\x70\x70\xF0\x8F\xC0\x12\xCA\x06\xCB\x9A\xE1\xD9\xCA\x33\x7A\x77\xD6\xF8\xEC\xB9\xF1\x68\x44\x42\x48\x13\xD2\xC0\xC2\xA4\xAE\x5E\x60\xFE\xB6\xA6\x05\xFC\xB4\xDD\x07\x59\x02\xD4\x59\x18\x98\x63\xF5\xA5\x63\xE0\x90\x0C\x7D\x5D\xB2\x06\x7A\xF3\x85\xEA\xEB\xD4\x03\xAE\x5E\x84\x3E\x5F\xFF\x15\xED\x69\xBC\xF9\x39\x36\x72\x75\xCF\x77\x52\x4D\xF3\xC9\x90\x2C\xB9\x3D\xE5\xC9\x23\x53\x3F\x1F\x24\x98\x21\x5C\x07\x99\x29\xBD\xC6\x3A\xEC\xE7\x6E\x86\x3A\x6B\x97\x74\x63\x33\xBD\x68\x18\x31\xF0\x78\x8D\x76\xBF\xFC\x9E\x8E\x5D\x2A\x86\xA7\x4D\x90\xDC\x27\x1A\x39\x02\x03\x01\x00\x01\xA3\x45\x30\x43\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xE5\x9D\x59\x30\x82\x47\x58\xCC\xAC\xFA\x08\x54\x36\x86\x7B\x3A\xB5\x04\x4D\xF0\x30\x12\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x08\x30\x06\x01\x01\xFF\x02\x01\x03\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x85\x0C\x5D\x8E\xE4\x6F\x51\x68\x42\x05\xA0\xDD\xBB\x4F\x27\x25\x84\x03\xBD\xF7\x64\xFD\x2D\xD7\x30\xE3\xA4\x10\x17\xEB\xDA\x29\x29\xB6\x79\x3F\x76\xF6\x19\x13\x23\xB8\x10\x0A\xF9\x58\xA4\xD4\x61\x70\xBD\x04\x61\x6A\x12\x8A\x17\xD5\x0A\xBD\xC5\xBC\x30\x7C\xD6\xE9\x0C\x25\x8D\x86\x40\x4F\xEC\xCC\xA3\x7E\x38\xC6\x37\x11\x4F\xED\xDD\x68\x31\x8E\x4C\xD2\xB3\x01\x74\xEE\xBE\x75\x5E\x07\x48\x1A\x7F\x70\xFF\x16\x5C\x84\xC0\x79\x85\xB8\x05\xFD\x7F\xBE\x65\x11\xA3\x0F\xC0\x02\xB4\xF8\x52\x37\x39\x04\xD5\xA9\x31\x7A\x18\xBF\xA0\x2A\xF4\x12\x99\xF7\xA3\x45\x82\xE3\x3C\x5E\xF5\x9D\x9E\xB5\xC8\x9E\x7C\x2E\xC8\xA4\x9E\x4E\x08\x14\x4B\x6D\xFD\x70\x6D\x6B\x1A\x63\xBD\x64\xE6\x1F\xB7\xCE\xF0\xF2\x9F\x2E\xBB\x1B\xB7\xF2\x50\x88\x73\x92\xC2\xE2\xE3\x16\x8D\x9A\x32\x02\xAB\x8E\x18\xDD\xE9\x10\x11\xEE\x7E\x35\xAB\x90\xAF\x3E\x30\x94\x7A\xD0\x33\x3D\xA7\x65\x0F\xF5\xFC\x8E\x9E\x62\xCF\x47\x44\x2C\x01\x5D\xBB\x1D\xB5\x32\xD2\x47\xD2\x38\x2E\xD0\xFE\x81\xDC\x32\x6A\x1E\xB5\xEE\x3C\xD5\xFC\xE7\x81\x1D\x19\xC3\x24\x42\xEA\x63\x39\xA9", ["CN=Equifax Secure Global eBusiness CA-1,O=Equifax Secure Inc.,C=US"] = "\x30\x82\x02\x90\x30\x82\x01\xF9\xA0\x03\x02\x01\x02\x02\x01\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x30\x5A\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x1C\x30\x1A\x06\x03\x55\x04\x0A\x13\x13\x45\x71\x75\x69\x66\x61\x78\x20\x53\x65\x63\x75\x72\x65\x20\x49\x6E\x63\x2E\x31\x2D\x30\x2B\x06\x03\x55\x04\x03\x13\x24\x45\x71\x75\x69\x66\x61\x78\x20\x53\x65\x63\x75\x72\x65\x20\x47\x6C\x6F\x62\x61\x6C\x20\x65\x42\x75\x73\x69\x6E\x65\x73\x73\x20\x43\x41\x2D\x31\x30\x1E\x17\x0D\x39\x39\x30\x36\x32\x31\x30\x34\x30\x30\x30\x30\x5A\x17\x0D\x32\x30\x30\x36\x32\x31\x30\x34\x30\x30\x30\x30\x5A\x30\x5A\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x1C\x30\x1A\x06\x03\x55\x04\x0A\x13\x13\x45\x71\x75\x69\x66\x61\x78\x20\x53\x65\x63\x75\x72\x65\x20\x49\x6E\x63\x2E\x31\x2D\x30\x2B\x06\x03\x55\x04\x03\x13\x24\x45\x71\x75\x69\x66\x61\x78\x20\x53\x65\x63\x75\x72\x65\x20\x47\x6C\x6F\x62\x61\x6C\x20\x65\x42\x75\x73\x69\x6E\x65\x73\x73\x20\x43\x41\x2D\x31\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\xBA\xE7\x17\x90\x02\x65\xB1\x34\x55\x3C\x49\xC2\x51\xD5\xDF\xA7\xD1\x37\x8F\xD1\xE7\x81\x73\x41\x52\x60\x9B\x9D\xA1\x17\x26\x78\xAD\xC7\xB1\xE8\x26\x94\x32\xB5\xDE\x33\x8D\x3A\x2F\xDB\xF2\x9A\x7A\x5A\x73\x98\xA3\x5C\xE9\xFB\x8A\x73\x1B\x5C\xE7\xC3\xBF\x80\x6C\xCD\xA9\xF4\xD6\x2B\xC0\xF7\xF9\x99\xAA\x63\xA2\xB1\x47\x02\x0F\xD4\xE4\x51\x3A\x12\x3C\x6C\x8A\x5A\x54\x84\x70\xDB\xC1\xC5\x90\xCF\x72\x45\xCB\xA8\x59\xC0\xCD\x33\x9D\x3F\xA3\x96\xEB\x85\x33\x21\x1C\x3E\x1E\x3E\x60\x6E\x76\x9C\x67\x85\xC5\xC8\xC3\x61\x02\x03\x01\x00\x01\xA3\x66\x30\x64\x30\x11\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x01\x04\x04\x03\x02\x00\x07\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\xBE\xA8\xA0\x74\x72\x50\x6B\x44\xB7\xC9\x23\xD8\xFB\xA8\xFF\xB3\x57\x6B\x68\x6C\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xBE\xA8\xA0\x74\x72\x50\x6B\x44\xB7\xC9\x23\xD8\xFB\xA8\xFF\xB3\x57\x6B\x68\x6C\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x03\x81\x81\x00\x30\xE2\x01\x51\xAA\xC7\xEA\x5F\xDA\xB9\xD0\x65\x0F\x30\xD6\x3E\xDA\x0D\x14\x49\x6E\x91\x93\x27\x14\x31\xEF\xC4\xF7\x2D\x45\xF8\xEC\xC7\xBF\xA2\x41\x0D\x23\xB4\x92\xF9\x19\x00\x67\xBD\x01\xAF\xCD\xE0\x71\xFC\x5A\xCF\x64\xC4\xE0\x96\x98\xD0\xA3\x40\xE2\x01\x8A\xEF\x27\x07\xF1\x65\x01\x8A\x44\x2D\x06\x65\x75\x52\xC0\x86\x10\x20\x21\x5F\x6C\x6B\x0F\x6C\xAE\x09\x1C\xAF\xF2\xA2\x18\x34\xC4\x75\xA4\x73\x1C\xF1\x8D\xDC\xEF\xAD\xF9\xB3\x76\xB4\x92\xBF\xDC\x95\x10\x1E\xBE\xCB\xC8\x3B\x5A\x84\x60\x19\x56\x94\xA9\x55", @@ -58,15 +53,11 @@ redef root_certs += { ["CN=Chambers of Commerce Root,OU=http://www.chambersign.org,O=AC Camerfirma SA CIF A82743287,C=EU"] = "\x30\x82\x04\xBD\x30\x82\x03\xA5\xA0\x03\x02\x01\x02\x02\x01\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x7F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x45\x55\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x13\x1E\x41\x43\x20\x43\x61\x6D\x65\x72\x66\x69\x72\x6D\x61\x20\x53\x41\x20\x43\x49\x46\x20\x41\x38\x32\x37\x34\x33\x32\x38\x37\x31\x23\x30\x21\x06\x03\x55\x04\x0B\x13\x1A\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x31\x22\x30\x20\x06\x03\x55\x04\x03\x13\x19\x43\x68\x61\x6D\x62\x65\x72\x73\x20\x6F\x66\x20\x43\x6F\x6D\x6D\x65\x72\x63\x65\x20\x52\x6F\x6F\x74\x30\x1E\x17\x0D\x30\x33\x30\x39\x33\x30\x31\x36\x31\x33\x34\x33\x5A\x17\x0D\x33\x37\x30\x39\x33\x30\x31\x36\x31\x33\x34\x34\x5A\x30\x7F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x45\x55\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x13\x1E\x41\x43\x20\x43\x61\x6D\x65\x72\x66\x69\x72\x6D\x61\x20\x53\x41\x20\x43\x49\x46\x20\x41\x38\x32\x37\x34\x33\x32\x38\x37\x31\x23\x30\x21\x06\x03\x55\x04\x0B\x13\x1A\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x31\x22\x30\x20\x06\x03\x55\x04\x03\x13\x19\x43\x68\x61\x6D\x62\x65\x72\x73\x20\x6F\x66\x20\x43\x6F\x6D\x6D\x65\x72\x63\x65\x20\x52\x6F\x6F\x74\x30\x82\x01\x20\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0D\x00\x30\x82\x01\x08\x02\x82\x01\x01\x00\xB7\x36\x55\xE5\xA5\x5D\x18\x30\xE0\xDA\x89\x54\x91\xFC\xC8\xC7\x52\xF8\x2F\x50\xD9\xEF\xB1\x75\x73\x65\x47\x7D\x1B\x5B\xBA\x75\xC5\xFC\xA1\x88\x24\xFA\x2F\xED\xCA\x08\x4A\x39\x54\xC4\x51\x7A\xB5\xDA\x60\xEA\x38\x3C\x81\xB2\xCB\xF1\xBB\xD9\x91\x23\x3F\x48\x01\x70\x75\xA9\x05\x2A\xAD\x1F\x71\xF3\xC9\x54\x3D\x1D\x06\x6A\x40\x3E\xB3\x0C\x85\xEE\x5C\x1B\x79\xC2\x62\xC4\xB8\x36\x8E\x35\x5D\x01\x0C\x23\x04\x47\x35\xAA\x9B\x60\x4E\xA0\x66\x3D\xCB\x26\x0A\x9C\x40\xA1\xF4\x5D\x98\xBF\x71\xAB\xA5\x00\x68\x2A\xED\x83\x7A\x0F\xA2\x14\xB5\xD4\x22\xB3\x80\xB0\x3C\x0C\x5A\x51\x69\x2D\x58\x18\x8F\xED\x99\x9E\xF1\xAE\xE2\x95\xE6\xF6\x47\xA8\xD6\x0C\x0F\xB0\x58\x58\xDB\xC3\x66\x37\x9E\x9B\x91\x54\x33\x37\xD2\x94\x1C\x6A\x48\xC9\xC9\xF2\xA5\xDA\xA5\x0C\x23\xF7\x23\x0E\x9C\x32\x55\x5E\x71\x9C\x84\x05\x51\x9A\x2D\xFD\xE6\x4E\x2A\x34\x5A\xDE\xCA\x40\x37\x67\x0C\x54\x21\x55\x77\xDA\x0A\x0C\xCC\x97\xAE\x80\xDC\x94\x36\x4A\xF4\x3E\xCE\x36\x13\x1E\x53\xE4\xAC\x4E\x3A\x05\xEC\xDB\xAE\x72\x9C\x38\x8B\xD0\x39\x3B\x89\x0A\x3E\x77\xFE\x75\x02\x01\x03\xA3\x82\x01\x44\x30\x82\x01\x40\x30\x12\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x08\x30\x06\x01\x01\xFF\x02\x01\x0C\x30\x3C\x06\x03\x55\x1D\x1F\x04\x35\x30\x33\x30\x31\xA0\x2F\xA0\x2D\x86\x2B\x68\x74\x74\x70\x3A\x2F\x2F\x63\x72\x6C\x2E\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x2F\x63\x68\x61\x6D\x62\x65\x72\x73\x72\x6F\x6F\x74\x2E\x63\x72\x6C\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xE3\x94\xF5\xB1\x4D\xE9\xDB\xA1\x29\x5B\x57\x8B\x4D\x76\x06\x76\xE1\xD1\xA2\x8A\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x11\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x01\x04\x04\x03\x02\x00\x07\x30\x27\x06\x03\x55\x1D\x11\x04\x20\x30\x1E\x81\x1C\x63\x68\x61\x6D\x62\x65\x72\x73\x72\x6F\x6F\x74\x40\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x30\x27\x06\x03\x55\x1D\x12\x04\x20\x30\x1E\x81\x1C\x63\x68\x61\x6D\x62\x65\x72\x73\x72\x6F\x6F\x74\x40\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x30\x58\x06\x03\x55\x1D\x20\x04\x51\x30\x4F\x30\x4D\x06\x0B\x2B\x06\x01\x04\x01\x81\x87\x2E\x0A\x03\x01\x30\x3E\x30\x3C\x06\x08\x2B\x06\x01\x05\x05\x07\x02\x01\x16\x30\x68\x74\x74\x70\x3A\x2F\x2F\x63\x70\x73\x2E\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x2F\x63\x70\x73\x2F\x63\x68\x61\x6D\x62\x65\x72\x73\x72\x6F\x6F\x74\x2E\x68\x74\x6D\x6C\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x0C\x41\x97\xC2\x1A\x86\xC0\x22\x7C\x9F\xFB\x90\xF3\x1A\xD1\x03\xB1\xEF\x13\xF9\x21\x5F\x04\x9C\xDA\xC9\xA5\x8D\x27\x6C\x96\x87\x91\xBE\x41\x90\x01\x72\x93\xE7\x1E\x7D\x5F\xF6\x89\xC6\x5D\xA7\x40\x09\x3D\xAC\x49\x45\x45\xDC\x2E\x8D\x30\x68\xB2\x09\xBA\xFB\xC3\x2F\xCC\xBA\x0B\xDF\x3F\x77\x7B\x46\x7D\x3A\x12\x24\x8E\x96\x8F\x3C\x05\x0A\x6F\xD2\x94\x28\x1D\x6D\x0C\xC0\x2E\x88\x22\xD5\xD8\xCF\x1D\x13\xC7\xF0\x48\xD7\xD7\x05\xA7\xCF\xC7\x47\x9E\x3B\x3C\x34\xC8\x80\x4F\xD4\x14\xBB\xFC\x0D\x50\xF7\xFA\xB3\xEC\x42\x5F\xA9\xDD\x6D\xC8\xF4\x75\xCF\x7B\xC1\x72\x26\xB1\x01\x1C\x5C\x2C\xFD\x7A\x4E\xB4\x01\xC5\x05\x57\xB9\xE7\x3C\xAA\x05\xD9\x88\xE9\x07\x46\x41\xCE\xEF\x41\x81\xAE\x58\xDF\x83\xA2\xAE\xCA\xD7\x77\x1F\xE7\x00\x3C\x9D\x6F\x8E\xE4\x32\x09\x1D\x4D\x78\x34\x78\x34\x3C\x94\x9B\x26\xED\x4F\x71\xC6\x19\x7A\xBD\x20\x22\x48\x5A\xFE\x4B\x7D\x03\xB7\xE7\x58\xBE\xC6\x32\x4E\x74\x1E\x68\xDD\xA8\x68\x5B\xB3\x3E\xEE\x62\x7D\xD9\x80\xE8\x0A\x75\x7A\xB7\xEE\xB4\x65\x9A\x21\x90\xE0\xAA\xD0\x98\xBC\x38\xB5\x73\x3C\x8B\xF8\xDC", ["CN=Global Chambersign Root,OU=http://www.chambersign.org,O=AC Camerfirma SA CIF A82743287,C=EU"] = "\x30\x82\x04\xC5\x30\x82\x03\xAD\xA0\x03\x02\x01\x02\x02\x01\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x7D\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x45\x55\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x13\x1E\x41\x43\x20\x43\x61\x6D\x65\x72\x66\x69\x72\x6D\x61\x20\x53\x41\x20\x43\x49\x46\x20\x41\x38\x32\x37\x34\x33\x32\x38\x37\x31\x23\x30\x21\x06\x03\x55\x04\x0B\x13\x1A\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x31\x20\x30\x1E\x06\x03\x55\x04\x03\x13\x17\x47\x6C\x6F\x62\x61\x6C\x20\x43\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x20\x52\x6F\x6F\x74\x30\x1E\x17\x0D\x30\x33\x30\x39\x33\x30\x31\x36\x31\x34\x31\x38\x5A\x17\x0D\x33\x37\x30\x39\x33\x30\x31\x36\x31\x34\x31\x38\x5A\x30\x7D\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x45\x55\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x13\x1E\x41\x43\x20\x43\x61\x6D\x65\x72\x66\x69\x72\x6D\x61\x20\x53\x41\x20\x43\x49\x46\x20\x41\x38\x32\x37\x34\x33\x32\x38\x37\x31\x23\x30\x21\x06\x03\x55\x04\x0B\x13\x1A\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x31\x20\x30\x1E\x06\x03\x55\x04\x03\x13\x17\x47\x6C\x6F\x62\x61\x6C\x20\x43\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x20\x52\x6F\x6F\x74\x30\x82\x01\x20\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0D\x00\x30\x82\x01\x08\x02\x82\x01\x01\x00\xA2\x70\xA2\xD0\x9F\x42\xAE\x5B\x17\xC7\xD8\x7D\xCF\x14\x83\xFC\x4F\xC9\xA1\xB7\x13\xAF\x8A\xD7\x9E\x3E\x04\x0A\x92\x8B\x60\x56\xFA\xB4\x32\x2F\x88\x4D\xA1\x60\x08\xF4\xB7\x09\x4E\xA0\x49\x2F\x49\xD6\xD3\xDF\x9D\x97\x5A\x9F\x94\x04\x70\xEC\x3F\x59\xD9\xB7\xCC\x66\x8B\x98\x52\x28\x09\x02\xDF\xC5\x2F\x84\x8D\x7A\x97\x77\xBF\xEC\x40\x9D\x25\x72\xAB\xB5\x3F\x32\x98\xFB\xB7\xB7\xFC\x72\x84\xE5\x35\x87\xF9\x55\xFA\xA3\x1F\x0E\x6F\x2E\x28\xDD\x69\xA0\xD9\x42\x10\xC6\xF8\xB5\x44\xC2\xD0\x43\x7F\xDB\xBC\xE4\xA2\x3C\x6A\x55\x78\x0A\x77\xA9\xD8\xEA\x19\x32\xB7\x2F\xFE\x5C\x3F\x1B\xEE\xB1\x98\xEC\xCA\xAD\x7A\x69\x45\xE3\x96\x0F\x55\xF6\xE6\xED\x75\xEA\x65\xE8\x32\x56\x93\x46\x89\xA8\x25\x8A\x65\x06\xEE\x6B\xBF\x79\x07\xD0\xF1\xB7\xAF\xED\x2C\x4D\x92\xBB\xC0\xA8\x5F\xA7\x67\x7D\x04\xF2\x15\x08\x70\xAC\x92\xD6\x7D\x04\xD2\x33\xFB\x4C\xB6\x0B\x0B\xFB\x1A\xC9\xC4\x8D\x03\xA9\x7E\x5C\xF2\x50\xAB\x12\xA5\xA1\xCF\x48\x50\xA5\xEF\xD2\xC8\x1A\x13\xFA\xB0\x7F\xB1\x82\x1C\x77\x6A\x0F\x5F\xDC\x0B\x95\x8F\xEF\x43\x7E\xE6\x45\x09\x25\x02\x01\x03\xA3\x82\x01\x50\x30\x82\x01\x4C\x30\x12\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x08\x30\x06\x01\x01\xFF\x02\x01\x0C\x30\x3F\x06\x03\x55\x1D\x1F\x04\x38\x30\x36\x30\x34\xA0\x32\xA0\x30\x86\x2E\x68\x74\x74\x70\x3A\x2F\x2F\x63\x72\x6C\x2E\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x2F\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x72\x6F\x6F\x74\x2E\x63\x72\x6C\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x43\x9C\x36\x9F\xB0\x9E\x30\x4D\xC6\xCE\x5F\xAD\x10\xAB\xE5\x03\xA5\xFA\xA9\x14\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x11\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x01\x04\x04\x03\x02\x00\x07\x30\x2A\x06\x03\x55\x1D\x11\x04\x23\x30\x21\x81\x1F\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x72\x6F\x6F\x74\x40\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x30\x2A\x06\x03\x55\x1D\x12\x04\x23\x30\x21\x81\x1F\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x72\x6F\x6F\x74\x40\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x30\x5B\x06\x03\x55\x1D\x20\x04\x54\x30\x52\x30\x50\x06\x0B\x2B\x06\x01\x04\x01\x81\x87\x2E\x0A\x01\x01\x30\x41\x30\x3F\x06\x08\x2B\x06\x01\x05\x05\x07\x02\x01\x16\x33\x68\x74\x74\x70\x3A\x2F\x2F\x63\x70\x73\x2E\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x2E\x6F\x72\x67\x2F\x63\x70\x73\x2F\x63\x68\x61\x6D\x62\x65\x72\x73\x69\x67\x6E\x72\x6F\x6F\x74\x2E\x68\x74\x6D\x6C\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x3C\x3B\x70\x91\xF9\x04\x54\x27\x91\xE1\xED\xED\xFE\x68\x7F\x61\x5D\xE5\x41\x65\x4F\x32\xF1\x18\x05\x94\x6A\x1C\xDE\x1F\x70\xDB\x3E\x7B\x32\x02\x34\xB5\x0C\x6C\xA1\x8A\x7C\xA5\xF4\x8F\xFF\xD4\xD8\xAD\x17\xD5\x2D\x04\xD1\x3F\x58\x80\xE2\x81\x59\x88\xBE\xC0\xE3\x46\x93\x24\xFE\x90\xBD\x26\xA2\x30\x2D\xE8\x97\x26\x57\x35\x89\x74\x96\x18\xF6\x15\xE2\xAF\x24\x19\x56\x02\x02\xB2\xBA\x0F\x14\xEA\xC6\x8A\x66\xC1\x86\x45\x55\x8B\xBE\x92\xBE\x9C\xA4\x04\xC7\x49\x3C\x9E\xE8\x29\x7A\x89\xD7\xFE\xAF\xFF\x68\xF5\xA5\x17\x90\xBD\xAC\x99\xCC\xA5\x86\x57\x09\x67\x46\xDB\xD6\x16\xC2\x46\xF1\xE4\xA9\x50\xF5\x8F\xD1\x92\x15\xD3\x5F\x3E\xC6\x00\x49\x3A\x6E\x58\xB2\xD1\xD1\x27\x0D\x25\xC8\x32\xF8\x20\x11\xCD\x7D\x32\x33\x48\x94\x54\x4C\xDD\xDC\x79\xC4\x30\x9F\xEB\x8E\xB8\x55\xB5\xD7\x88\x5C\xC5\x6A\x24\x3D\xB2\xD3\x05\x03\x51\xC6\x07\xEF\xCC\x14\x72\x74\x3D\x6E\x72\xCE\x18\x28\x8C\x4A\xA0\x77\xE5\x09\x2B\x45\x44\x47\xAC\xB7\x67\x7F\x01\x8A\x05\x5A\x93\xBE\xA1\xC1\xFF\xF8\xE7\x0E\x67\xA4\x47\x49\x76\x5D\x75\x90\x1A\xF5\x26\x8F\xF0", ["CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado,OU=Tanusitvanykiadok,O=NetLock Halozatbiztonsagi Kft.,L=Budapest,ST=Hungary,C=HU"] = "\x30\x82\x06\x7D\x30\x82\x05\x65\xA0\x03\x02\x01\x02\x02\x02\x01\x03\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x30\x81\xAF\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x48\x55\x31\x10\x30\x0E\x06\x03\x55\x04\x08\x13\x07\x48\x75\x6E\x67\x61\x72\x79\x31\x11\x30\x0F\x06\x03\x55\x04\x07\x13\x08\x42\x75\x64\x61\x70\x65\x73\x74\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x13\x1E\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x48\x61\x6C\x6F\x7A\x61\x74\x62\x69\x7A\x74\x6F\x6E\x73\x61\x67\x69\x20\x4B\x66\x74\x2E\x31\x1A\x30\x18\x06\x03\x55\x04\x0B\x13\x11\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x6B\x31\x36\x30\x34\x06\x03\x55\x04\x03\x13\x2D\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x4B\x6F\x7A\x6A\x65\x67\x79\x7A\x6F\x69\x20\x28\x43\x6C\x61\x73\x73\x20\x41\x29\x20\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x30\x1E\x17\x0D\x39\x39\x30\x32\x32\x34\x32\x33\x31\x34\x34\x37\x5A\x17\x0D\x31\x39\x30\x32\x31\x39\x32\x33\x31\x34\x34\x37\x5A\x30\x81\xAF\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x48\x55\x31\x10\x30\x0E\x06\x03\x55\x04\x08\x13\x07\x48\x75\x6E\x67\x61\x72\x79\x31\x11\x30\x0F\x06\x03\x55\x04\x07\x13\x08\x42\x75\x64\x61\x70\x65\x73\x74\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x13\x1E\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x48\x61\x6C\x6F\x7A\x61\x74\x62\x69\x7A\x74\x6F\x6E\x73\x61\x67\x69\x20\x4B\x66\x74\x2E\x31\x1A\x30\x18\x06\x03\x55\x04\x0B\x13\x11\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x6B\x31\x36\x30\x34\x06\x03\x55\x04\x03\x13\x2D\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x4B\x6F\x7A\x6A\x65\x67\x79\x7A\x6F\x69\x20\x28\x43\x6C\x61\x73\x73\x20\x41\x29\x20\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xBC\x74\x8C\x0F\xBB\x4C\xF4\x37\x1E\xA9\x05\x82\xD8\xE6\xE1\x6C\x70\xEA\x78\xB5\x6E\xD1\x38\x44\x0D\xA8\x83\xCE\x5D\xD2\xD6\xD5\x81\xC5\xD4\x4B\xE7\x5B\x94\x70\x26\xDB\x3B\x9D\x6A\x4C\x62\xF7\x71\xF3\x64\xD6\x61\x3B\x3D\xEB\x73\xA3\x37\xD9\xCF\xEA\x8C\x92\x3B\xCD\xF7\x07\xDC\x66\x74\x97\xF4\x45\x22\xDD\xF4\x5C\xE0\xBF\x6D\xF3\xBE\x65\x33\xE4\x15\x3A\xBF\xDB\x98\x90\x55\x38\xC4\xED\xA6\x55\x63\x0B\xB0\x78\x04\xF4\xE3\x6E\xC1\x3F\x8E\xFC\x51\x78\x1F\x92\x9E\x83\xC2\xFE\xD9\xB0\xA9\xC9\xBC\x5A\x00\xFF\xA9\xA8\x98\x74\xFB\xF6\x2C\x3E\x15\x39\x0D\xB6\x04\x55\xA8\x0E\x98\x20\x42\xB3\xB1\x25\xAD\x7E\x9A\x6F\x5D\x53\xB1\xAB\x0C\xFC\xEB\xE0\xF3\x7A\xB3\xA8\xB3\xFF\x46\xF6\x63\xA2\xD8\x3A\x98\x7B\xB6\xAC\x85\xFF\xB0\x25\x4F\x74\x63\xE7\x13\x07\xA5\x0A\x8F\x05\xF7\xC0\x64\x6F\x7E\xA7\x27\x80\x96\xDE\xD4\x2E\x86\x60\xC7\x6B\x2B\x5E\x73\x7B\x17\xE7\x91\x3F\x64\x0C\xD8\x4B\x22\x34\x2B\x9B\x32\xF2\x48\x1F\x9F\xA1\x0A\x84\x7A\xE2\xC2\xAD\x97\x3D\x8E\xD5\xC1\xF9\x56\xA3\x50\xE9\xC6\xB4\xFA\x98\xA2\xEE\x95\xE6\x2A\x03\x8C\xDF\x02\x03\x01\x00\x01\xA3\x82\x02\x9F\x30\x82\x02\x9B\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x00\x06\x30\x12\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x08\x30\x06\x01\x01\xFF\x02\x01\x04\x30\x11\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x01\x04\x04\x03\x02\x00\x07\x30\x82\x02\x60\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x0D\x04\x82\x02\x51\x16\x82\x02\x4D\x46\x49\x47\x59\x45\x4C\x45\x4D\x21\x20\x45\x7A\x65\x6E\x20\x74\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x20\x61\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x4B\x66\x74\x2E\x20\x41\x6C\x74\x61\x6C\x61\x6E\x6F\x73\x20\x53\x7A\x6F\x6C\x67\x61\x6C\x74\x61\x74\x61\x73\x69\x20\x46\x65\x6C\x74\x65\x74\x65\x6C\x65\x69\x62\x65\x6E\x20\x6C\x65\x69\x72\x74\x20\x65\x6C\x6A\x61\x72\x61\x73\x6F\x6B\x20\x61\x6C\x61\x70\x6A\x61\x6E\x20\x6B\x65\x73\x7A\x75\x6C\x74\x2E\x20\x41\x20\x68\x69\x74\x65\x6C\x65\x73\x69\x74\x65\x73\x20\x66\x6F\x6C\x79\x61\x6D\x61\x74\x61\x74\x20\x61\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x4B\x66\x74\x2E\x20\x74\x65\x72\x6D\x65\x6B\x66\x65\x6C\x65\x6C\x6F\x73\x73\x65\x67\x2D\x62\x69\x7A\x74\x6F\x73\x69\x74\x61\x73\x61\x20\x76\x65\x64\x69\x2E\x20\x41\x20\x64\x69\x67\x69\x74\x61\x6C\x69\x73\x20\x61\x6C\x61\x69\x72\x61\x73\x20\x65\x6C\x66\x6F\x67\x61\x64\x61\x73\x61\x6E\x61\x6B\x20\x66\x65\x6C\x74\x65\x74\x65\x6C\x65\x20\x61\x7A\x20\x65\x6C\x6F\x69\x72\x74\x20\x65\x6C\x6C\x65\x6E\x6F\x72\x7A\x65\x73\x69\x20\x65\x6C\x6A\x61\x72\x61\x73\x20\x6D\x65\x67\x74\x65\x74\x65\x6C\x65\x2E\x20\x41\x7A\x20\x65\x6C\x6A\x61\x72\x61\x73\x20\x6C\x65\x69\x72\x61\x73\x61\x20\x6D\x65\x67\x74\x61\x6C\x61\x6C\x68\x61\x74\x6F\x20\x61\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x4B\x66\x74\x2E\x20\x49\x6E\x74\x65\x72\x6E\x65\x74\x20\x68\x6F\x6E\x6C\x61\x70\x6A\x61\x6E\x20\x61\x20\x68\x74\x74\x70\x73\x3A\x2F\x2F\x77\x77\x77\x2E\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x2F\x64\x6F\x63\x73\x20\x63\x69\x6D\x65\x6E\x20\x76\x61\x67\x79\x20\x6B\x65\x72\x68\x65\x74\x6F\x20\x61\x7A\x20\x65\x6C\x6C\x65\x6E\x6F\x72\x7A\x65\x73\x40\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x20\x65\x2D\x6D\x61\x69\x6C\x20\x63\x69\x6D\x65\x6E\x2E\x20\x49\x4D\x50\x4F\x52\x54\x41\x4E\x54\x21\x20\x54\x68\x65\x20\x69\x73\x73\x75\x61\x6E\x63\x65\x20\x61\x6E\x64\x20\x74\x68\x65\x20\x75\x73\x65\x20\x6F\x66\x20\x74\x68\x69\x73\x20\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x69\x73\x20\x73\x75\x62\x6A\x65\x63\x74\x20\x74\x6F\x20\x74\x68\x65\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x43\x50\x53\x20\x61\x76\x61\x69\x6C\x61\x62\x6C\x65\x20\x61\x74\x20\x68\x74\x74\x70\x73\x3A\x2F\x2F\x77\x77\x77\x2E\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x2F\x64\x6F\x63\x73\x20\x6F\x72\x20\x62\x79\x20\x65\x2D\x6D\x61\x69\x6C\x20\x61\x74\x20\x63\x70\x73\x40\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x2E\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x03\x82\x01\x01\x00\x48\x24\x46\xF7\xBA\x56\x6F\xFA\xC8\x28\x03\x40\x4E\xE5\x31\x39\x6B\x26\x6B\x53\x7F\xDB\xDF\xDF\xF3\x71\x3D\x26\xC0\x14\x0E\xC6\x67\x7B\x23\xA8\x0C\x73\xDD\x01\xBB\xC6\xCA\x6E\x37\x39\x55\xD5\xC7\x8C\x56\x20\x0E\x28\x0A\x0E\xD2\x2A\xA4\xB0\x49\x52\xC6\x38\x07\xFE\xBE\x0A\x09\x8C\xD1\x98\xCF\xCA\xDA\x14\x31\xA1\x4F\xD2\x39\xFC\x0F\x11\x2C\x43\xC3\xDD\xAB\x93\xC7\x55\x3E\x47\x7C\x18\x1A\x00\xDC\xF3\x7B\xD8\xF2\x7F\x52\x6C\x20\xF4\x0B\x5F\x69\x52\xF4\xEE\xF8\xB2\x29\x60\xEB\xE3\x49\x31\x21\x0D\xD6\xB5\x10\x41\xE2\x41\x09\x6C\xE2\x1A\x9A\x56\x4B\x77\x02\xF6\xA0\x9B\x9A\x27\x87\xE8\x55\x29\x71\xC2\x90\x9F\x45\x78\x1A\xE1\x15\x64\x3D\xD0\x0E\xD8\xA0\x76\x9F\xAE\xC5\xD0\x2E\xEA\xD6\x0F\x56\xEC\x64\x7F\x5A\x9B\x14\x58\x01\x27\x7E\x13\x50\xC7\x6B\x2A\xE6\x68\x3C\xBF\x5C\xA0\x0A\x1B\xE1\x0E\x7A\xE9\xE2\x80\xC3\xE9\xE9\xF6\xFD\x6C\x11\x9E\xD0\xE5\x28\x27\x2B\x54\x32\x42\x14\x82\x75\xE6\x4A\xF0\x2B\x66\x75\x63\x8C\xA2\xFB\x04\x3E\x83\x0E\x9B\x36\xF0\x18\xE4\x26\x20\xC3\x8C\xF0\x28\x07\xAD\x3C\x17\x66\x88\xB5\xFD\xB6\x88", - ["CN=NetLock Uzleti (Class B) Tanusitvanykiado,OU=Tanusitvanykiadok,O=NetLock Halozatbiztonsagi Kft.,L=Budapest,C=HU"] = "\x30\x82\x05\x4B\x30\x82\x04\xB4\xA0\x03\x02\x01\x02\x02\x01\x69\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x30\x81\x99\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x48\x55\x31\x11\x30\x0F\x06\x03\x55\x04\x07\x13\x08\x42\x75\x64\x61\x70\x65\x73\x74\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x13\x1E\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x48\x61\x6C\x6F\x7A\x61\x74\x62\x69\x7A\x74\x6F\x6E\x73\x61\x67\x69\x20\x4B\x66\x74\x2E\x31\x1A\x30\x18\x06\x03\x55\x04\x0B\x13\x11\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x6B\x31\x32\x30\x30\x06\x03\x55\x04\x03\x13\x29\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x55\x7A\x6C\x65\x74\x69\x20\x28\x43\x6C\x61\x73\x73\x20\x42\x29\x20\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x30\x1E\x17\x0D\x39\x39\x30\x32\x32\x35\x31\x34\x31\x30\x32\x32\x5A\x17\x0D\x31\x39\x30\x32\x32\x30\x31\x34\x31\x30\x32\x32\x5A\x30\x81\x99\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x48\x55\x31\x11\x30\x0F\x06\x03\x55\x04\x07\x13\x08\x42\x75\x64\x61\x70\x65\x73\x74\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x13\x1E\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x48\x61\x6C\x6F\x7A\x61\x74\x62\x69\x7A\x74\x6F\x6E\x73\x61\x67\x69\x20\x4B\x66\x74\x2E\x31\x1A\x30\x18\x06\x03\x55\x04\x0B\x13\x11\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x6B\x31\x32\x30\x30\x06\x03\x55\x04\x03\x13\x29\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x55\x7A\x6C\x65\x74\x69\x20\x28\x43\x6C\x61\x73\x73\x20\x42\x29\x20\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\xB1\xEA\x04\xEC\x20\xA0\x23\xC2\x8F\x38\x60\xCF\xC7\x46\xB3\xD5\x1B\xFE\xFB\xB9\x99\x9E\x04\xDC\x1C\x7F\x8C\x4A\x81\x98\xEE\xA4\xD4\xCA\x8A\x17\xB9\x22\x7F\x83\x0A\x75\x4C\x9B\xC0\x69\xD8\x64\x39\xA3\xED\x92\xA3\xFD\x5B\x5C\x74\x1A\xC0\x47\xCA\x3A\x69\x76\x9A\xBA\xE2\x44\x17\xFC\x4C\xA3\xD5\xFE\xB8\x97\x88\xAF\x88\x03\x89\x1F\xA4\xF2\x04\x3E\xC8\x07\x0B\xE6\xF9\xB3\x2F\x7A\x62\x14\x09\x46\x14\xCA\x64\xF5\x8B\x80\xB5\x62\xA8\xD8\x6B\xD6\x71\x93\x2D\xB3\xBF\x09\x54\x58\xED\x06\xEB\xA8\x7B\xDC\x43\xB1\xA1\x69\x02\x03\x01\x00\x01\xA3\x82\x02\x9F\x30\x82\x02\x9B\x30\x12\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x08\x30\x06\x01\x01\xFF\x02\x01\x04\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x00\x06\x30\x11\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x01\x04\x04\x03\x02\x00\x07\x30\x82\x02\x60\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x0D\x04\x82\x02\x51\x16\x82\x02\x4D\x46\x49\x47\x59\x45\x4C\x45\x4D\x21\x20\x45\x7A\x65\x6E\x20\x74\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x20\x61\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x4B\x66\x74\x2E\x20\x41\x6C\x74\x61\x6C\x61\x6E\x6F\x73\x20\x53\x7A\x6F\x6C\x67\x61\x6C\x74\x61\x74\x61\x73\x69\x20\x46\x65\x6C\x74\x65\x74\x65\x6C\x65\x69\x62\x65\x6E\x20\x6C\x65\x69\x72\x74\x20\x65\x6C\x6A\x61\x72\x61\x73\x6F\x6B\x20\x61\x6C\x61\x70\x6A\x61\x6E\x20\x6B\x65\x73\x7A\x75\x6C\x74\x2E\x20\x41\x20\x68\x69\x74\x65\x6C\x65\x73\x69\x74\x65\x73\x20\x66\x6F\x6C\x79\x61\x6D\x61\x74\x61\x74\x20\x61\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x4B\x66\x74\x2E\x20\x74\x65\x72\x6D\x65\x6B\x66\x65\x6C\x65\x6C\x6F\x73\x73\x65\x67\x2D\x62\x69\x7A\x74\x6F\x73\x69\x74\x61\x73\x61\x20\x76\x65\x64\x69\x2E\x20\x41\x20\x64\x69\x67\x69\x74\x61\x6C\x69\x73\x20\x61\x6C\x61\x69\x72\x61\x73\x20\x65\x6C\x66\x6F\x67\x61\x64\x61\x73\x61\x6E\x61\x6B\x20\x66\x65\x6C\x74\x65\x74\x65\x6C\x65\x20\x61\x7A\x20\x65\x6C\x6F\x69\x72\x74\x20\x65\x6C\x6C\x65\x6E\x6F\x72\x7A\x65\x73\x69\x20\x65\x6C\x6A\x61\x72\x61\x73\x20\x6D\x65\x67\x74\x65\x74\x65\x6C\x65\x2E\x20\x41\x7A\x20\x65\x6C\x6A\x61\x72\x61\x73\x20\x6C\x65\x69\x72\x61\x73\x61\x20\x6D\x65\x67\x74\x61\x6C\x61\x6C\x68\x61\x74\x6F\x20\x61\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x4B\x66\x74\x2E\x20\x49\x6E\x74\x65\x72\x6E\x65\x74\x20\x68\x6F\x6E\x6C\x61\x70\x6A\x61\x6E\x20\x61\x20\x68\x74\x74\x70\x73\x3A\x2F\x2F\x77\x77\x77\x2E\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x2F\x64\x6F\x63\x73\x20\x63\x69\x6D\x65\x6E\x20\x76\x61\x67\x79\x20\x6B\x65\x72\x68\x65\x74\x6F\x20\x61\x7A\x20\x65\x6C\x6C\x65\x6E\x6F\x72\x7A\x65\x73\x40\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x20\x65\x2D\x6D\x61\x69\x6C\x20\x63\x69\x6D\x65\x6E\x2E\x20\x49\x4D\x50\x4F\x52\x54\x41\x4E\x54\x21\x20\x54\x68\x65\x20\x69\x73\x73\x75\x61\x6E\x63\x65\x20\x61\x6E\x64\x20\x74\x68\x65\x20\x75\x73\x65\x20\x6F\x66\x20\x74\x68\x69\x73\x20\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x69\x73\x20\x73\x75\x62\x6A\x65\x63\x74\x20\x74\x6F\x20\x74\x68\x65\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x43\x50\x53\x20\x61\x76\x61\x69\x6C\x61\x62\x6C\x65\x20\x61\x74\x20\x68\x74\x74\x70\x73\x3A\x2F\x2F\x77\x77\x77\x2E\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x2F\x64\x6F\x63\x73\x20\x6F\x72\x20\x62\x79\x20\x65\x2D\x6D\x61\x69\x6C\x20\x61\x74\x20\x63\x70\x73\x40\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x2E\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x03\x81\x81\x00\x04\xDB\xAE\x8C\x17\xAF\xF8\x0E\x90\x31\x4E\xCD\x3E\x09\xC0\x6D\x3A\xB0\xF8\x33\x4C\x47\x4C\xE3\x75\x88\x10\x97\xAC\xB0\x38\x15\x91\xC6\x29\x96\xCC\x21\xC0\x6D\x3C\xA5\x74\xCF\xD8\x82\xA5\x39\xC3\x65\xE3\x42\x70\xBB\x22\x90\xE3\x7D\xDB\x35\x76\xE1\xA0\xB5\xDA\x9F\x70\x6E\x93\x1A\x30\x39\x1D\x30\xDB\x2E\xE3\x7C\xB2\x91\xB2\xD1\x37\x29\xFA\xB9\xD6\x17\x5C\x47\x4F\xE3\x1D\x38\xEB\x9F\xD5\x7B\x95\xA8\x28\x9E\x15\x4A\xD1\xD1\xD0\x2B\x00\x97\xA0\xE2\x92\x36\x2B\x63\xAC\x58\x01\x6B\x33\x29\x50\x86\x83\xF1\x01\x48", - ["CN=NetLock Expressz (Class C) Tanusitvanykiado,OU=Tanusitvanykiadok,O=NetLock Halozatbiztonsagi Kft.,L=Budapest,C=HU"] = "\x30\x82\x05\x4F\x30\x82\x04\xB8\xA0\x03\x02\x01\x02\x02\x01\x68\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x30\x81\x9B\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x48\x55\x31\x11\x30\x0F\x06\x03\x55\x04\x07\x13\x08\x42\x75\x64\x61\x70\x65\x73\x74\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x13\x1E\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x48\x61\x6C\x6F\x7A\x61\x74\x62\x69\x7A\x74\x6F\x6E\x73\x61\x67\x69\x20\x4B\x66\x74\x2E\x31\x1A\x30\x18\x06\x03\x55\x04\x0B\x13\x11\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x6B\x31\x34\x30\x32\x06\x03\x55\x04\x03\x13\x2B\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x45\x78\x70\x72\x65\x73\x73\x7A\x20\x28\x43\x6C\x61\x73\x73\x20\x43\x29\x20\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x30\x1E\x17\x0D\x39\x39\x30\x32\x32\x35\x31\x34\x30\x38\x31\x31\x5A\x17\x0D\x31\x39\x30\x32\x32\x30\x31\x34\x30\x38\x31\x31\x5A\x30\x81\x9B\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x48\x55\x31\x11\x30\x0F\x06\x03\x55\x04\x07\x13\x08\x42\x75\x64\x61\x70\x65\x73\x74\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x13\x1E\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x48\x61\x6C\x6F\x7A\x61\x74\x62\x69\x7A\x74\x6F\x6E\x73\x61\x67\x69\x20\x4B\x66\x74\x2E\x31\x1A\x30\x18\x06\x03\x55\x04\x0B\x13\x11\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x6B\x31\x34\x30\x32\x06\x03\x55\x04\x03\x13\x2B\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x45\x78\x70\x72\x65\x73\x73\x7A\x20\x28\x43\x6C\x61\x73\x73\x20\x43\x29\x20\x54\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x6B\x69\x61\x64\x6F\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\xEB\xEC\xB0\x6C\x61\x8A\x23\x25\xAF\x60\x20\xE3\xD9\x9F\xFC\x93\x0B\xDB\x5D\x8D\xB0\xA1\xB3\x40\x3A\x82\xCE\xFD\x75\xE0\x78\x32\x03\x86\x5A\x86\x95\x91\xED\x53\xFA\x9D\x40\xFC\xE6\xE8\xDD\xD9\x5B\x7A\x03\xBD\x5D\xF3\x3B\x0C\xC3\x51\x79\x9B\xAD\x55\xA0\xE9\xD0\x03\x10\xAF\x0A\xBA\x14\x42\xD9\x52\x26\x11\x22\xC7\xD2\x20\xCC\x82\xA4\x9A\xA9\xFE\xB8\x81\x76\x9D\x6A\xB7\xD2\x36\x75\x3E\xB1\x86\x09\xF6\x6E\x6D\x7E\x4E\xB7\x7A\xEC\xAE\x71\x84\xF6\x04\x33\x08\x25\x32\xEB\x74\xAC\x16\x44\xC6\xE4\x40\x93\x1D\x7F\xAD\x02\x03\x01\x00\x01\xA3\x82\x02\x9F\x30\x82\x02\x9B\x30\x12\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x08\x30\x06\x01\x01\xFF\x02\x01\x04\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x00\x06\x30\x11\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x01\x04\x04\x03\x02\x00\x07\x30\x82\x02\x60\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x0D\x04\x82\x02\x51\x16\x82\x02\x4D\x46\x49\x47\x59\x45\x4C\x45\x4D\x21\x20\x45\x7A\x65\x6E\x20\x74\x61\x6E\x75\x73\x69\x74\x76\x61\x6E\x79\x20\x61\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x4B\x66\x74\x2E\x20\x41\x6C\x74\x61\x6C\x61\x6E\x6F\x73\x20\x53\x7A\x6F\x6C\x67\x61\x6C\x74\x61\x74\x61\x73\x69\x20\x46\x65\x6C\x74\x65\x74\x65\x6C\x65\x69\x62\x65\x6E\x20\x6C\x65\x69\x72\x74\x20\x65\x6C\x6A\x61\x72\x61\x73\x6F\x6B\x20\x61\x6C\x61\x70\x6A\x61\x6E\x20\x6B\x65\x73\x7A\x75\x6C\x74\x2E\x20\x41\x20\x68\x69\x74\x65\x6C\x65\x73\x69\x74\x65\x73\x20\x66\x6F\x6C\x79\x61\x6D\x61\x74\x61\x74\x20\x61\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x4B\x66\x74\x2E\x20\x74\x65\x72\x6D\x65\x6B\x66\x65\x6C\x65\x6C\x6F\x73\x73\x65\x67\x2D\x62\x69\x7A\x74\x6F\x73\x69\x74\x61\x73\x61\x20\x76\x65\x64\x69\x2E\x20\x41\x20\x64\x69\x67\x69\x74\x61\x6C\x69\x73\x20\x61\x6C\x61\x69\x72\x61\x73\x20\x65\x6C\x66\x6F\x67\x61\x64\x61\x73\x61\x6E\x61\x6B\x20\x66\x65\x6C\x74\x65\x74\x65\x6C\x65\x20\x61\x7A\x20\x65\x6C\x6F\x69\x72\x74\x20\x65\x6C\x6C\x65\x6E\x6F\x72\x7A\x65\x73\x69\x20\x65\x6C\x6A\x61\x72\x61\x73\x20\x6D\x65\x67\x74\x65\x74\x65\x6C\x65\x2E\x20\x41\x7A\x20\x65\x6C\x6A\x61\x72\x61\x73\x20\x6C\x65\x69\x72\x61\x73\x61\x20\x6D\x65\x67\x74\x61\x6C\x61\x6C\x68\x61\x74\x6F\x20\x61\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x4B\x66\x74\x2E\x20\x49\x6E\x74\x65\x72\x6E\x65\x74\x20\x68\x6F\x6E\x6C\x61\x70\x6A\x61\x6E\x20\x61\x20\x68\x74\x74\x70\x73\x3A\x2F\x2F\x77\x77\x77\x2E\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x2F\x64\x6F\x63\x73\x20\x63\x69\x6D\x65\x6E\x20\x76\x61\x67\x79\x20\x6B\x65\x72\x68\x65\x74\x6F\x20\x61\x7A\x20\x65\x6C\x6C\x65\x6E\x6F\x72\x7A\x65\x73\x40\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x20\x65\x2D\x6D\x61\x69\x6C\x20\x63\x69\x6D\x65\x6E\x2E\x20\x49\x4D\x50\x4F\x52\x54\x41\x4E\x54\x21\x20\x54\x68\x65\x20\x69\x73\x73\x75\x61\x6E\x63\x65\x20\x61\x6E\x64\x20\x74\x68\x65\x20\x75\x73\x65\x20\x6F\x66\x20\x74\x68\x69\x73\x20\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x69\x73\x20\x73\x75\x62\x6A\x65\x63\x74\x20\x74\x6F\x20\x74\x68\x65\x20\x4E\x65\x74\x4C\x6F\x63\x6B\x20\x43\x50\x53\x20\x61\x76\x61\x69\x6C\x61\x62\x6C\x65\x20\x61\x74\x20\x68\x74\x74\x70\x73\x3A\x2F\x2F\x77\x77\x77\x2E\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x2F\x64\x6F\x63\x73\x20\x6F\x72\x20\x62\x79\x20\x65\x2D\x6D\x61\x69\x6C\x20\x61\x74\x20\x63\x70\x73\x40\x6E\x65\x74\x6C\x6F\x63\x6B\x2E\x6E\x65\x74\x2E\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04\x05\x00\x03\x81\x81\x00\x10\xAD\x7F\xD7\x0C\x32\x80\x0A\xD8\x86\xF1\x79\x98\xB5\xAD\xD4\xCD\xB3\x36\xC4\x96\x48\xC1\x5C\xCD\x9A\xD9\x05\x2E\x9F\xBE\x50\xEB\xF4\x26\x14\x10\x2D\xD4\x66\x17\xF8\x9E\xC1\x27\xFD\xF1\xED\xE4\x7B\x4B\xA0\x6C\xB5\xAB\x9A\x57\x70\xA6\xED\xA0\xA4\xED\x2E\xF5\xFD\xFC\xBD\xFE\x4D\x37\x08\x0C\xBC\xE3\x96\x83\x22\xF5\x49\x1B\x7F\x4B\x2B\xB4\x54\xC1\x80\x7C\x99\x4E\x1D\xD0\x8C\xEE\xD0\xAC\xE5\x92\xFA\x75\x56\xFE\x64\xA0\x13\x8F\xB8\xB8\x16\x9D\x61\x05\x67\x80\xC8\xD0\xD8\xA5\x07\x02\x34\x98\x04\x8D\x33\x04\xD4", ["CN=XRamp Global Certification Authority,O=XRamp Security Services Inc,OU=www.xrampsecurity.com,C=US"] = "\x30\x82\x04\x30\x30\x82\x03\x18\xA0\x03\x02\x01\x02\x02\x10\x50\x94\x6C\xEC\x18\xEA\xD5\x9C\x4D\xD5\x97\xEF\x75\x8F\xA0\xAD\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x81\x82\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x1E\x30\x1C\x06\x03\x55\x04\x0B\x13\x15\x77\x77\x77\x2E\x78\x72\x61\x6D\x70\x73\x65\x63\x75\x72\x69\x74\x79\x2E\x63\x6F\x6D\x31\x24\x30\x22\x06\x03\x55\x04\x0A\x13\x1B\x58\x52\x61\x6D\x70\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x53\x65\x72\x76\x69\x63\x65\x73\x20\x49\x6E\x63\x31\x2D\x30\x2B\x06\x03\x55\x04\x03\x13\x24\x58\x52\x61\x6D\x70\x20\x47\x6C\x6F\x62\x61\x6C\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x1E\x17\x0D\x30\x34\x31\x31\x30\x31\x31\x37\x31\x34\x30\x34\x5A\x17\x0D\x33\x35\x30\x31\x30\x31\x30\x35\x33\x37\x31\x39\x5A\x30\x81\x82\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x1E\x30\x1C\x06\x03\x55\x04\x0B\x13\x15\x77\x77\x77\x2E\x78\x72\x61\x6D\x70\x73\x65\x63\x75\x72\x69\x74\x79\x2E\x63\x6F\x6D\x31\x24\x30\x22\x06\x03\x55\x04\x0A\x13\x1B\x58\x52\x61\x6D\x70\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x53\x65\x72\x76\x69\x63\x65\x73\x20\x49\x6E\x63\x31\x2D\x30\x2B\x06\x03\x55\x04\x03\x13\x24\x58\x52\x61\x6D\x70\x20\x47\x6C\x6F\x62\x61\x6C\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\x98\x24\x1E\xBD\x15\xB4\xBA\xDF\xC7\x8C\xA5\x27\xB6\x38\x0B\x69\xF3\xB6\x4E\xA8\x2C\x2E\x21\x1D\x5C\x44\xDF\x21\x5D\x7E\x23\x74\xFE\x5E\x7E\xB4\x4A\xB7\xA6\xAD\x1F\xAE\xE0\x06\x16\xE2\x9B\x5B\xD9\x67\x74\x6B\x5D\x80\x8F\x29\x9D\x86\x1B\xD9\x9C\x0D\x98\x6D\x76\x10\x28\x58\xE4\x65\xB0\x7F\x4A\x98\x79\x9F\xE0\xC3\x31\x7E\x80\x2B\xB5\x8C\xC0\x40\x3B\x11\x86\xD0\xCB\xA2\x86\x36\x60\xA4\xD5\x30\x82\x6D\xD9\x6E\xD0\x0F\x12\x04\x33\x97\x5F\x4F\x61\x5A\xF0\xE4\xF9\x91\xAB\xE7\x1D\x3B\xBC\xE8\xCF\xF4\x6B\x2D\x34\x7C\xE2\x48\x61\x1C\x8E\xF3\x61\x44\xCC\x6F\xA0\x4A\xA9\x94\xB0\x4D\xDA\xE7\xA9\x34\x7A\x72\x38\xA8\x41\xCC\x3C\x94\x11\x7D\xEB\xC8\xA6\x8C\xB7\x86\xCB\xCA\x33\x3B\xD9\x3D\x37\x8B\xFB\x7A\x3E\x86\x2C\xE7\x73\xD7\x0A\x57\xAC\x64\x9B\x19\xEB\xF4\x0F\x04\x08\x8A\xAC\x03\x17\x19\x64\xF4\x5A\x25\x22\x8D\x34\x2C\xB2\xF6\x68\x1D\x12\x6D\xD3\x8A\x1E\x14\xDA\xC4\x8F\xA6\xE2\x23\x85\xD5\x7A\x0D\xBD\x6A\xE0\xE9\xEC\xEC\x17\xBB\x42\x1B\x67\xAA\x25\xED\x45\x83\x21\xFC\xC1\xC9\x7C\xD5\x62\x3E\xFA\xF2\xC5\x2D\xD3\xFD\xD4\x65\x02\x03\x01\x00\x01\xA3\x81\x9F\x30\x81\x9C\x30\x13\x06\x09\x2B\x06\x01\x04\x01\x82\x37\x14\x02\x04\x06\x1E\x04\x00\x43\x00\x41\x30\x0B\x06\x03\x55\x1D\x0F\x04\x04\x03\x02\x01\x86\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xC6\x4F\xA2\x3D\x06\x63\x84\x09\x9C\xCE\x62\xE4\x04\xAC\x8D\x5C\xB5\xE9\xB6\x1B\x30\x36\x06\x03\x55\x1D\x1F\x04\x2F\x30\x2D\x30\x2B\xA0\x29\xA0\x27\x86\x25\x68\x74\x74\x70\x3A\x2F\x2F\x63\x72\x6C\x2E\x78\x72\x61\x6D\x70\x73\x65\x63\x75\x72\x69\x74\x79\x2E\x63\x6F\x6D\x2F\x58\x47\x43\x41\x2E\x63\x72\x6C\x30\x10\x06\x09\x2B\x06\x01\x04\x01\x82\x37\x15\x01\x04\x03\x02\x01\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x91\x15\x39\x03\x01\x1B\x67\xFB\x4A\x1C\xF9\x0A\x60\x5B\xA1\xDA\x4D\x97\x62\xF9\x24\x53\x27\xD7\x82\x64\x4E\x90\x2E\xC3\x49\x1B\x2B\x9A\xDC\xFC\xA8\x78\x67\x35\xF1\x1D\xF0\x11\xBD\xB7\x48\xE3\x10\xF6\x0D\xDF\x3F\xD2\xC9\xB6\xAA\x55\xA4\x48\xBA\x02\xDB\xDE\x59\x2E\x15\x5B\x3B\x9D\x16\x7D\x47\xD7\x37\xEA\x5F\x4D\x76\x12\x36\xBB\x1F\xD7\xA1\x81\x04\x46\x20\xA3\x2C\x6D\xA9\x9E\x01\x7E\x3F\x29\xCE\x00\x93\xDF\xFD\xC9\x92\x73\x89\x89\x64\x9E\xE7\x2B\xE4\x1C\x91\x2C\xD2\xB9\xCE\x7D\xCE\x6F\x31\x99\xD3\xE6\xBE\xD2\x1E\x90\xF0\x09\x14\x79\x5C\x23\xAB\x4D\xD2\xDA\x21\x1F\x4D\x99\x79\x9D\xE1\xCF\x27\x9F\x10\x9B\x1C\x88\x0D\xB0\x8A\x64\x41\x31\xB8\x0E\x6C\x90\x24\xA4\x9B\x5C\x71\x8F\xBA\xBB\x7E\x1C\x1B\xDB\x6A\x80\x0F\x21\xBC\xE9\xDB\xA6\xB7\x40\xF4\xB2\x8B\xA9\xB1\xE4\xEF\x9A\x1A\xD0\x3D\x69\x99\xEE\xA8\x28\xA3\xE1\x3C\xB3\xF0\xB2\x11\x9C\xCF\x7C\x40\xE6\xDD\xE7\x43\x7D\xA2\xD8\x3A\xB5\xA9\x8D\xF2\x34\x99\xC4\xD4\x10\xE1\x06\xFD\x09\x84\x10\x3B\xEE\xC4\x4C\xF4\xEC\x27\x7C\x42\xC2\x74\x7C\x82\x8A\x09\xC9\xB4\x03\x25\xBC", ["OU=Go Daddy Class 2 Certification Authority,O=The Go Daddy Group\, Inc.,C=US"] = "\x30\x82\x04\x00\x30\x82\x02\xE8\xA0\x03\x02\x01\x02\x02\x01\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x63\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x21\x30\x1F\x06\x03\x55\x04\x0A\x13\x18\x54\x68\x65\x20\x47\x6F\x20\x44\x61\x64\x64\x79\x20\x47\x72\x6F\x75\x70\x2C\x20\x49\x6E\x63\x2E\x31\x31\x30\x2F\x06\x03\x55\x04\x0B\x13\x28\x47\x6F\x20\x44\x61\x64\x64\x79\x20\x43\x6C\x61\x73\x73\x20\x32\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x1E\x17\x0D\x30\x34\x30\x36\x32\x39\x31\x37\x30\x36\x32\x30\x5A\x17\x0D\x33\x34\x30\x36\x32\x39\x31\x37\x30\x36\x32\x30\x5A\x30\x63\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x21\x30\x1F\x06\x03\x55\x04\x0A\x13\x18\x54\x68\x65\x20\x47\x6F\x20\x44\x61\x64\x64\x79\x20\x47\x72\x6F\x75\x70\x2C\x20\x49\x6E\x63\x2E\x31\x31\x30\x2F\x06\x03\x55\x04\x0B\x13\x28\x47\x6F\x20\x44\x61\x64\x64\x79\x20\x43\x6C\x61\x73\x73\x20\x32\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x82\x01\x20\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0D\x00\x30\x82\x01\x08\x02\x82\x01\x01\x00\xDE\x9D\xD7\xEA\x57\x18\x49\xA1\x5B\xEB\xD7\x5F\x48\x86\xEA\xBE\xDD\xFF\xE4\xEF\x67\x1C\xF4\x65\x68\xB3\x57\x71\xA0\x5E\x77\xBB\xED\x9B\x49\xE9\x70\x80\x3D\x56\x18\x63\x08\x6F\xDA\xF2\xCC\xD0\x3F\x7F\x02\x54\x22\x54\x10\xD8\xB2\x81\xD4\xC0\x75\x3D\x4B\x7F\xC7\x77\xC3\x3E\x78\xAB\x1A\x03\xB5\x20\x6B\x2F\x6A\x2B\xB1\xC5\x88\x7E\xC4\xBB\x1E\xB0\xC1\xD8\x45\x27\x6F\xAA\x37\x58\xF7\x87\x26\xD7\xD8\x2D\xF6\xA9\x17\xB7\x1F\x72\x36\x4E\xA6\x17\x3F\x65\x98\x92\xDB\x2A\x6E\x5D\xA2\xFE\x88\xE0\x0B\xDE\x7F\xE5\x8D\x15\xE1\xEB\xCB\x3A\xD5\xE2\x12\xA2\x13\x2D\xD8\x8E\xAF\x5F\x12\x3D\xA0\x08\x05\x08\xB6\x5C\xA5\x65\x38\x04\x45\x99\x1E\xA3\x60\x60\x74\xC5\x41\xA5\x72\x62\x1B\x62\xC5\x1F\x6F\x5F\x1A\x42\xBE\x02\x51\x65\xA8\xAE\x23\x18\x6A\xFC\x78\x03\xA9\x4D\x7F\x80\xC3\xFA\xAB\x5A\xFC\xA1\x40\xA4\xCA\x19\x16\xFE\xB2\xC8\xEF\x5E\x73\x0D\xEE\x77\xBD\x9A\xF6\x79\x98\xBC\xB1\x07\x67\xA2\x15\x0D\xDD\xA0\x58\xC6\x44\x7B\x0A\x3E\x62\x28\x5F\xBA\x41\x07\x53\x58\xCF\x11\x7E\x38\x74\xC5\xF8\xFF\xB5\x69\x90\x8F\x84\x74\xEA\x97\x1B\xAF\x02\x01\x03\xA3\x81\xC0\x30\x81\xBD\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xD2\xC4\xB0\xD2\x91\xD4\x4C\x11\x71\xB3\x61\xCB\x3D\xA1\xFE\xDD\xA8\x6A\xD4\xE3\x30\x81\x8D\x06\x03\x55\x1D\x23\x04\x81\x85\x30\x81\x82\x80\x14\xD2\xC4\xB0\xD2\x91\xD4\x4C\x11\x71\xB3\x61\xCB\x3D\xA1\xFE\xDD\xA8\x6A\xD4\xE3\xA1\x67\xA4\x65\x30\x63\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x21\x30\x1F\x06\x03\x55\x04\x0A\x13\x18\x54\x68\x65\x20\x47\x6F\x20\x44\x61\x64\x64\x79\x20\x47\x72\x6F\x75\x70\x2C\x20\x49\x6E\x63\x2E\x31\x31\x30\x2F\x06\x03\x55\x04\x0B\x13\x28\x47\x6F\x20\x44\x61\x64\x64\x79\x20\x43\x6C\x61\x73\x73\x20\x32\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x82\x01\x00\x30\x0C\x06\x03\x55\x1D\x13\x04\x05\x30\x03\x01\x01\xFF\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x32\x4B\xF3\xB2\xCA\x3E\x91\xFC\x12\xC6\xA1\x07\x8C\x8E\x77\xA0\x33\x06\x14\x5C\x90\x1E\x18\xF7\x08\xA6\x3D\x0A\x19\xF9\x87\x80\x11\x6E\x69\xE4\x96\x17\x30\xFF\x34\x91\x63\x72\x38\xEE\xCC\x1C\x01\xA3\x1D\x94\x28\xA4\x31\xF6\x7A\xC4\x54\xD7\xF6\xE5\x31\x58\x03\xA2\xCC\xCE\x62\xDB\x94\x45\x73\xB5\xBF\x45\xC9\x24\xB5\xD5\x82\x02\xAD\x23\x79\x69\x8D\xB8\xB6\x4D\xCE\xCF\x4C\xCA\x33\x23\xE8\x1C\x88\xAA\x9D\x8B\x41\x6E\x16\xC9\x20\xE5\x89\x9E\xCD\x3B\xDA\x70\xF7\x7E\x99\x26\x20\x14\x54\x25\xAB\x6E\x73\x85\xE6\x9B\x21\x9D\x0A\x6C\x82\x0E\xA8\xF8\xC2\x0C\xFA\x10\x1E\x6C\x96\xEF\x87\x0D\xC4\x0F\x61\x8B\xAD\xEE\x83\x2B\x95\xF8\x8E\x92\x84\x72\x39\xEB\x20\xEA\x83\xED\x83\xCD\x97\x6E\x08\xBC\xEB\x4E\x26\xB6\x73\x2B\xE4\xD3\xF6\x4C\xFE\x26\x71\xE2\x61\x11\x74\x4A\xFF\x57\x1A\x87\x0F\x75\x48\x2E\xCF\x51\x69\x17\xA0\x02\x12\x61\x95\xD5\xD1\x40\xB2\x10\x4C\xEE\xC4\xAC\x10\x43\xA6\xA5\x9E\x0A\xD5\x95\x62\x9A\x0D\xCF\x88\x82\xC5\x32\x0C\xE4\x2B\x9F\x45\xE6\x0D\x9F\x28\x9C\xB1\xB9\x2A\x5A\x57\xAD\x37\x0F\xAF\x1D\x7F\xDB\xBD\x9F", ["OU=Starfield Class 2 Certification Authority,O=Starfield Technologies\, Inc.,C=US"] = "\x30\x82\x04\x0F\x30\x82\x02\xF7\xA0\x03\x02\x01\x02\x02\x01\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x68\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x25\x30\x23\x06\x03\x55\x04\x0A\x13\x1C\x53\x74\x61\x72\x66\x69\x65\x6C\x64\x20\x54\x65\x63\x68\x6E\x6F\x6C\x6F\x67\x69\x65\x73\x2C\x20\x49\x6E\x63\x2E\x31\x32\x30\x30\x06\x03\x55\x04\x0B\x13\x29\x53\x74\x61\x72\x66\x69\x65\x6C\x64\x20\x43\x6C\x61\x73\x73\x20\x32\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x1E\x17\x0D\x30\x34\x30\x36\x32\x39\x31\x37\x33\x39\x31\x36\x5A\x17\x0D\x33\x34\x30\x36\x32\x39\x31\x37\x33\x39\x31\x36\x5A\x30\x68\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x25\x30\x23\x06\x03\x55\x04\x0A\x13\x1C\x53\x74\x61\x72\x66\x69\x65\x6C\x64\x20\x54\x65\x63\x68\x6E\x6F\x6C\x6F\x67\x69\x65\x73\x2C\x20\x49\x6E\x63\x2E\x31\x32\x30\x30\x06\x03\x55\x04\x0B\x13\x29\x53\x74\x61\x72\x66\x69\x65\x6C\x64\x20\x43\x6C\x61\x73\x73\x20\x32\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x82\x01\x20\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0D\x00\x30\x82\x01\x08\x02\x82\x01\x01\x00\xB7\x32\xC8\xFE\xE9\x71\xA6\x04\x85\xAD\x0C\x11\x64\xDF\xCE\x4D\xEF\xC8\x03\x18\x87\x3F\xA1\xAB\xFB\x3C\xA6\x9F\xF0\xC3\xA1\xDA\xD4\xD8\x6E\x2B\x53\x90\xFB\x24\xA4\x3E\x84\xF0\x9E\xE8\x5F\xEC\xE5\x27\x44\xF5\x28\xA6\x3F\x7B\xDE\xE0\x2A\xF0\xC8\xAF\x53\x2F\x9E\xCA\x05\x01\x93\x1E\x8F\x66\x1C\x39\xA7\x4D\xFA\x5A\xB6\x73\x04\x25\x66\xEB\x77\x7F\xE7\x59\xC6\x4A\x99\x25\x14\x54\xEB\x26\xC7\xF3\x7F\x19\xD5\x30\x70\x8F\xAF\xB0\x46\x2A\xFF\xAD\xEB\x29\xED\xD7\x9F\xAA\x04\x87\xA3\xD4\xF9\x89\xA5\x34\x5F\xDB\x43\x91\x82\x36\xD9\x66\x3C\xB1\xB8\xB9\x82\xFD\x9C\x3A\x3E\x10\xC8\x3B\xEF\x06\x65\x66\x7A\x9B\x19\x18\x3D\xFF\x71\x51\x3C\x30\x2E\x5F\xBE\x3D\x77\x73\xB2\x5D\x06\x6C\xC3\x23\x56\x9A\x2B\x85\x26\x92\x1C\xA7\x02\xB3\xE4\x3F\x0D\xAF\x08\x79\x82\xB8\x36\x3D\xEA\x9C\xD3\x35\xB3\xBC\x69\xCA\xF5\xCC\x9D\xE8\xFD\x64\x8D\x17\x80\x33\x6E\x5E\x4A\x5D\x99\xC9\x1E\x87\xB4\x9D\x1A\xC0\xD5\x6E\x13\x35\x23\x5E\xDF\x9B\x5F\x3D\xEF\xD6\xF7\x76\xC2\xEA\x3E\xBB\x78\x0D\x1C\x42\x67\x6B\x04\xD8\xF8\xD6\xDA\x6F\x8B\xF2\x44\xA0\x01\xAB\x02\x01\x03\xA3\x81\xC5\x30\x81\xC2\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xBF\x5F\xB7\xD1\xCE\xDD\x1F\x86\xF4\x5B\x55\xAC\xDC\xD7\x10\xC2\x0E\xA9\x88\xE7\x30\x81\x92\x06\x03\x55\x1D\x23\x04\x81\x8A\x30\x81\x87\x80\x14\xBF\x5F\xB7\xD1\xCE\xDD\x1F\x86\xF4\x5B\x55\xAC\xDC\xD7\x10\xC2\x0E\xA9\x88\xE7\xA1\x6C\xA4\x6A\x30\x68\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x25\x30\x23\x06\x03\x55\x04\x0A\x13\x1C\x53\x74\x61\x72\x66\x69\x65\x6C\x64\x20\x54\x65\x63\x68\x6E\x6F\x6C\x6F\x67\x69\x65\x73\x2C\x20\x49\x6E\x63\x2E\x31\x32\x30\x30\x06\x03\x55\x04\x0B\x13\x29\x53\x74\x61\x72\x66\x69\x65\x6C\x64\x20\x43\x6C\x61\x73\x73\x20\x32\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x82\x01\x00\x30\x0C\x06\x03\x55\x1D\x13\x04\x05\x30\x03\x01\x01\xFF\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x05\x9D\x3F\x88\x9D\xD1\xC9\x1A\x55\xA1\xAC\x69\xF3\xF3\x59\xDA\x9B\x01\x87\x1A\x4F\x57\xA9\xA1\x79\x09\x2A\xDB\xF7\x2F\xB2\x1E\xCC\xC7\x5E\x6A\xD8\x83\x87\xA1\x97\xEF\x49\x35\x3E\x77\x06\x41\x58\x62\xBF\x8E\x58\xB8\x0A\x67\x3F\xEC\xB3\xDD\x21\x66\x1F\xC9\x54\xFA\x72\xCC\x3D\x4C\x40\xD8\x81\xAF\x77\x9E\x83\x7A\xBB\xA2\xC7\xF5\x34\x17\x8E\xD9\x11\x40\xF4\xFC\x2C\x2A\x4D\x15\x7F\xA7\x62\x5D\x2E\x25\xD3\x00\x0B\x20\x1A\x1D\x68\xF9\x17\xB8\xF4\xBD\x8B\xED\x28\x59\xDD\x4D\x16\x8B\x17\x83\xC8\xB2\x65\xC7\x2D\x7A\xA5\xAA\xBC\x53\x86\x6D\xDD\x57\xA4\xCA\xF8\x20\x41\x0B\x68\xF0\xF4\xFB\x74\xBE\x56\x5D\x7A\x79\xF5\xF9\x1D\x85\xE3\x2D\x95\xBE\xF5\x71\x90\x43\xCC\x8D\x1F\x9A\x00\x0A\x87\x29\xE9\x55\x22\x58\x00\x23\xEA\xE3\x12\x43\x29\x5B\x47\x08\xDD\x8C\x41\x6A\x65\x06\xA8\xE5\x21\xAA\x41\xB4\x95\x21\x95\xB9\x7D\xD1\x34\xAB\x13\xD6\xAD\xBC\xDC\xE2\x3D\x39\xCD\xBD\x3E\x75\x70\xA1\x18\x59\x03\xC9\x22\xB4\x8F\x9C\xD5\x5E\x2A\xD7\xA5\xB6\xD4\x0A\x6D\xF8\xB7\x40\x11\x46\x9A\x1F\x79\x0E\x62\xBF\x0F\x97\xEC\xE0\x2F\x1F\x17\x94", ["CN=StartCom Certification Authority,OU=Secure Digital Certificate Signing,O=StartCom Ltd.,C=IL"] = "\x30\x82\x07\xC9\x30\x82\x05\xB1\xA0\x03\x02\x01\x02\x02\x01\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x7D\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x49\x4C\x31\x16\x30\x14\x06\x03\x55\x04\x0A\x13\x0D\x53\x74\x61\x72\x74\x43\x6F\x6D\x20\x4C\x74\x64\x2E\x31\x2B\x30\x29\x06\x03\x55\x04\x0B\x13\x22\x53\x65\x63\x75\x72\x65\x20\x44\x69\x67\x69\x74\x61\x6C\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x53\x69\x67\x6E\x69\x6E\x67\x31\x29\x30\x27\x06\x03\x55\x04\x03\x13\x20\x53\x74\x61\x72\x74\x43\x6F\x6D\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x1E\x17\x0D\x30\x36\x30\x39\x31\x37\x31\x39\x34\x36\x33\x36\x5A\x17\x0D\x33\x36\x30\x39\x31\x37\x31\x39\x34\x36\x33\x36\x5A\x30\x7D\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x49\x4C\x31\x16\x30\x14\x06\x03\x55\x04\x0A\x13\x0D\x53\x74\x61\x72\x74\x43\x6F\x6D\x20\x4C\x74\x64\x2E\x31\x2B\x30\x29\x06\x03\x55\x04\x0B\x13\x22\x53\x65\x63\x75\x72\x65\x20\x44\x69\x67\x69\x74\x61\x6C\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x53\x69\x67\x6E\x69\x6E\x67\x31\x29\x30\x27\x06\x03\x55\x04\x03\x13\x20\x53\x74\x61\x72\x74\x43\x6F\x6D\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\xC1\x88\xDB\x09\xBC\x6C\x46\x7C\x78\x9F\x95\x7B\xB5\x33\x90\xF2\x72\x62\xD6\xC1\x36\x20\x22\x24\x5E\xCE\xE9\x77\xF2\x43\x0A\xA2\x06\x64\xA4\xCC\x8E\x36\xF8\x38\xE6\x23\xF0\x6E\x6D\xB1\x3C\xDD\x72\xA3\x85\x1C\xA1\xD3\x3D\xB4\x33\x2B\xD3\x2F\xAF\xFE\xEA\xB0\x41\x59\x67\xB6\xC4\x06\x7D\x0A\x9E\x74\x85\xD6\x79\x4C\x80\x37\x7A\xDF\x39\x05\x52\x59\xF7\xF4\x1B\x46\x43\xA4\xD2\x85\x85\xD2\xC3\x71\xF3\x75\x62\x34\xBA\x2C\x8A\x7F\x1E\x8F\xEE\xED\x34\xD0\x11\xC7\x96\xCD\x52\x3D\xBA\x33\xD6\xDD\x4D\xDE\x0B\x3B\x4A\x4B\x9F\xC2\x26\x2F\xFA\xB5\x16\x1C\x72\x35\x77\xCA\x3C\x5D\xE6\xCA\xE1\x26\x8B\x1A\x36\x76\x5C\x01\xDB\x74\x14\x25\xFE\xED\xB5\xA0\x88\x0F\xDD\x78\xCA\x2D\x1F\x07\x97\x30\x01\x2D\x72\x79\xFA\x46\xD6\x13\x2A\xA8\xB9\xA6\xAB\x83\x49\x1D\xE5\xF2\xEF\xDD\xE4\x01\x8E\x18\x0A\x8F\x63\x53\x16\x85\x62\xA9\x0E\x19\x3A\xCC\xB5\x66\xA6\xC2\x6B\x74\x07\xE4\x2B\xE1\x76\x3E\xB4\x6D\xD8\xF6\x44\xE1\x73\x62\x1F\x3B\xC4\xBE\xA0\x53\x56\x25\x6C\x51\x09\xF7\xAA\xAB\xCA\xBF\x76\xFD\x6D\x9B\xF3\x9D\xDB\xBF\x3D\x66\xBC\x0C\x56\xAA\xAF\x98\x48\x95\x3A\x4B\xDF\xA7\x58\x50\xD9\x38\x75\xA9\x5B\xEA\x43\x0C\x02\xFF\x99\xEB\xE8\x6C\x4D\x70\x5B\x29\x65\x9C\xDD\xAA\x5D\xCC\xAF\x01\x31\xEC\x0C\xEB\xD2\x8D\xE8\xEA\x9C\x7B\xE6\x6E\xF7\x27\x66\x0C\x1A\x48\xD7\x6E\x42\xE3\x3F\xDE\x21\x3E\x7B\xE1\x0D\x70\xFB\x63\xAA\xA8\x6C\x1A\x54\xB4\x5C\x25\x7A\xC9\xA2\xC9\x8B\x16\xA6\xBB\x2C\x7E\x17\x5E\x05\x4D\x58\x6E\x12\x1D\x01\xEE\x12\x10\x0D\xC6\x32\x7F\x18\xFF\xFC\xF4\xFA\xCD\x6E\x91\xE8\x36\x49\xBE\x1A\x48\x69\x8B\xC2\x96\x4D\x1A\x12\xB2\x69\x17\xC1\x0A\x90\xD6\xFA\x79\x22\x48\xBF\xBA\x7B\x69\xF8\x70\xC7\xFA\x7A\x37\xD8\xD8\x0D\xD2\x76\x4F\x57\xFF\x90\xB7\xE3\x91\xD2\xDD\xEF\xC2\x60\xB7\x67\x3A\xDD\xFE\xAA\x9C\xF0\xD4\x8B\x7F\x72\x22\xCE\xC6\x9F\x97\xB6\xF8\xAF\x8A\xA0\x10\xA8\xD9\xFB\x18\xC6\xB6\xB5\x5C\x52\x3C\x89\xB6\x19\x2A\x73\x01\x0A\x0F\x03\xB3\x12\x60\xF2\x7A\x2F\x81\xDB\xA3\x6E\xFF\x26\x30\x97\xF5\x8B\xDD\x89\x57\xB6\xAD\x3D\xB3\xAF\x2B\xC5\xB7\x76\x02\xF0\xA5\xD6\x2B\x9A\x86\x14\x2A\x72\xF6\xE3\x33\x8C\x5D\x09\x4B\x13\xDF\xBB\x8C\x74\x13\x52\x4B\x02\x03\x01\x00\x01\xA3\x82\x02\x52\x30\x82\x02\x4E\x30\x0C\x06\x03\x55\x1D\x13\x04\x05\x30\x03\x01\x01\xFF\x30\x0B\x06\x03\x55\x1D\x0F\x04\x04\x03\x02\x01\xAE\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x4E\x0B\xEF\x1A\xA4\x40\x5B\xA5\x17\x69\x87\x30\xCA\x34\x68\x43\xD0\x41\xAE\xF2\x30\x64\x06\x03\x55\x1D\x1F\x04\x5D\x30\x5B\x30\x2C\xA0\x2A\xA0\x28\x86\x26\x68\x74\x74\x70\x3A\x2F\x2F\x63\x65\x72\x74\x2E\x73\x74\x61\x72\x74\x63\x6F\x6D\x2E\x6F\x72\x67\x2F\x73\x66\x73\x63\x61\x2D\x63\x72\x6C\x2E\x63\x72\x6C\x30\x2B\xA0\x29\xA0\x27\x86\x25\x68\x74\x74\x70\x3A\x2F\x2F\x63\x72\x6C\x2E\x73\x74\x61\x72\x74\x63\x6F\x6D\x2E\x6F\x72\x67\x2F\x73\x66\x73\x63\x61\x2D\x63\x72\x6C\x2E\x63\x72\x6C\x30\x82\x01\x5D\x06\x03\x55\x1D\x20\x04\x82\x01\x54\x30\x82\x01\x50\x30\x82\x01\x4C\x06\x0B\x2B\x06\x01\x04\x01\x81\xB5\x37\x01\x01\x01\x30\x82\x01\x3B\x30\x2F\x06\x08\x2B\x06\x01\x05\x05\x07\x02\x01\x16\x23\x68\x74\x74\x70\x3A\x2F\x2F\x63\x65\x72\x74\x2E\x73\x74\x61\x72\x74\x63\x6F\x6D\x2E\x6F\x72\x67\x2F\x70\x6F\x6C\x69\x63\x79\x2E\x70\x64\x66\x30\x35\x06\x08\x2B\x06\x01\x05\x05\x07\x02\x01\x16\x29\x68\x74\x74\x70\x3A\x2F\x2F\x63\x65\x72\x74\x2E\x73\x74\x61\x72\x74\x63\x6F\x6D\x2E\x6F\x72\x67\x2F\x69\x6E\x74\x65\x72\x6D\x65\x64\x69\x61\x74\x65\x2E\x70\x64\x66\x30\x81\xD0\x06\x08\x2B\x06\x01\x05\x05\x07\x02\x02\x30\x81\xC3\x30\x27\x16\x20\x53\x74\x61\x72\x74\x20\x43\x6F\x6D\x6D\x65\x72\x63\x69\x61\x6C\x20\x28\x53\x74\x61\x72\x74\x43\x6F\x6D\x29\x20\x4C\x74\x64\x2E\x30\x03\x02\x01\x01\x1A\x81\x97\x4C\x69\x6D\x69\x74\x65\x64\x20\x4C\x69\x61\x62\x69\x6C\x69\x74\x79\x2C\x20\x72\x65\x61\x64\x20\x74\x68\x65\x20\x73\x65\x63\x74\x69\x6F\x6E\x20\x2A\x4C\x65\x67\x61\x6C\x20\x4C\x69\x6D\x69\x74\x61\x74\x69\x6F\x6E\x73\x2A\x20\x6F\x66\x20\x74\x68\x65\x20\x53\x74\x61\x72\x74\x43\x6F\x6D\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x20\x50\x6F\x6C\x69\x63\x79\x20\x61\x76\x61\x69\x6C\x61\x62\x6C\x65\x20\x61\x74\x20\x68\x74\x74\x70\x3A\x2F\x2F\x63\x65\x72\x74\x2E\x73\x74\x61\x72\x74\x63\x6F\x6D\x2E\x6F\x72\x67\x2F\x70\x6F\x6C\x69\x63\x79\x2E\x70\x64\x66\x30\x11\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x01\x04\x04\x03\x02\x00\x07\x30\x38\x06\x09\x60\x86\x48\x01\x86\xF8\x42\x01\x0D\x04\x2B\x16\x29\x53\x74\x61\x72\x74\x43\x6F\x6D\x20\x46\x72\x65\x65\x20\x53\x53\x4C\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x02\x01\x00\x16\x6C\x99\xF4\x66\x0C\x34\xF5\xD0\x85\x5E\x7D\x0A\xEC\xDA\x10\x4E\x38\x1C\x5E\xDF\xA6\x25\x05\x4B\x91\x32\xC1\xE8\x3B\xF1\x3D\xDD\x44\x09\x5B\x07\x49\x8A\x29\xCB\x66\x02\xB7\xB1\x9A\xF7\x25\x98\x09\x3C\x8E\x1B\xE1\xDD\x36\x87\x2B\x4B\xBB\x68\xD3\x39\x66\x3D\xA0\x26\xC7\xF2\x39\x91\x1D\x51\xAB\x82\x7B\x7E\xD5\xCE\x5A\xE4\xE2\x03\x57\x70\x69\x97\x08\xF9\x5E\x58\xA6\x0A\xDF\x8C\x06\x9A\x45\x16\x16\x38\x0A\x5E\x57\xF6\x62\xC7\x7A\x02\x05\xE6\xBC\x1E\xB5\xF2\x9E\xF4\xA9\x29\x83\xF8\xB2\x14\xE3\x6E\x28\x87\x44\xC3\x90\x1A\xDE\x38\xA9\x3C\xAC\x43\x4D\x64\x45\xCE\xDD\x28\xA9\x5C\xF2\x73\x7B\x04\xF8\x17\xE8\xAB\xB1\xF3\x2E\x5C\x64\x6E\x73\x31\x3A\x12\xB8\xBC\xB3\x11\xE4\x7D\x8F\x81\x51\x9A\x3B\x8D\x89\xF4\x4D\x93\x66\x7B\x3C\x03\xED\xD3\x9A\x1D\x9A\xF3\x65\x50\xF5\xA0\xD0\x75\x9F\x2F\xAF\xF0\xEA\x82\x43\x98\xF8\x69\x9C\x89\x79\xC4\x43\x8E\x46\x72\xE3\x64\x36\x12\xAF\xF7\x25\x1E\x38\x89\x90\x77\x7E\xC3\x6B\x6A\xB9\xC3\xCB\x44\x4B\xAC\x78\x90\x8B\xE7\xC7\x2C\x1E\x4B\x11\x44\xC8\x34\x52\x27\xCD\x0A\x5D\x9F\x85\xC1\x89\xD5\x1A\x78\xF2\x95\x10\x53\x32\xDD\x80\x84\x66\x75\xD9\xB5\x68\x28\xFB\x61\x2E\xBE\x84\xA8\x38\xC0\x99\x12\x86\xA5\x1E\x67\x64\xAD\x06\x2E\x2F\xA9\x70\x85\xC7\x96\x0F\x7C\x89\x65\xF5\x8E\x43\x54\x0E\xAB\xDD\xA5\x80\x39\x94\x60\xC0\x34\xC9\x96\x70\x2C\xA3\x12\xF5\x1F\x48\x7B\xBD\x1C\x7E\x6B\xB7\x9D\x90\xF4\x22\x3B\xAE\xF8\xFC\x2A\xCA\xFA\x82\x52\xA0\xEF\xAF\x4B\x55\x93\xEB\xC1\xB5\xF0\x22\x8B\xAC\x34\x4E\x26\x22\x04\xA1\x87\x2C\x75\x4A\xB7\xE5\x7D\x13\xD7\xB8\x0C\x64\xC0\x36\xD2\xC9\x2F\x86\x12\x8C\x23\x09\xC1\x1B\x82\x3B\x73\x49\xA3\x6A\x57\x87\x94\xE5\xD6\x78\xC5\x99\x43\x63\xE3\x4D\xE0\x77\x2D\xE1\x65\x99\x72\x69\x04\x1A\x47\x09\xE6\x0F\x01\x56\x24\xFB\x1F\xBF\x0E\x79\xA9\x58\x2E\xB9\xC4\x09\x01\x7E\x95\xBA\x6D\x00\x06\x3E\xB2\xEA\x4A\x10\x39\xD8\xD0\x2B\xF5\xBF\xEC\x75\xBF\x97\x02\xC5\x09\x1B\x08\xDC\x55\x37\xE2\x81\xFB\x37\x84\x43\x62\x20\xCA\xE7\x56\x4B\x65\xEA\xFE\x6C\xC1\x24\x93\x24\xA1\x34\xEB\x05\xFF\x9A\x22\xAE\x9B\x7D\x3F\xF1\x65\x51\x0A\xA6\x30\x6A\xB3\xF4\x88\x1C\x80\x0D\xFC\x72\x8A\xE8\x83\x5E", ["O=Government Root Certification Authority,C=TW"] = "\x30\x82\x05\x72\x30\x82\x03\x5A\xA0\x03\x02\x01\x02\x02\x10\x1F\x9D\x59\x5A\xD7\x2F\xC2\x06\x44\xA5\x80\x08\x69\xE3\x5E\xF6\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x3F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x54\x57\x31\x30\x30\x2E\x06\x03\x55\x04\x0A\x0C\x27\x47\x6F\x76\x65\x72\x6E\x6D\x65\x6E\x74\x20\x52\x6F\x6F\x74\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x1E\x17\x0D\x30\x32\x31\x32\x30\x35\x31\x33\x32\x33\x33\x33\x5A\x17\x0D\x33\x32\x31\x32\x30\x35\x31\x33\x32\x33\x33\x33\x5A\x30\x3F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x54\x57\x31\x30\x30\x2E\x06\x03\x55\x04\x0A\x0C\x27\x47\x6F\x76\x65\x72\x6E\x6D\x65\x6E\x74\x20\x52\x6F\x6F\x74\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\x9A\x25\xB8\xEC\xCC\xA2\x75\xA8\x7B\xF7\xCE\x5B\x59\x8A\xC9\xD1\x86\x12\x08\x54\xEC\x9C\xF2\xE7\x46\xF6\x88\xF3\x7C\xE9\xA5\xDF\x4C\x47\x36\xA4\x1B\x01\x1C\x7F\x1E\x57\x8A\x8D\xC3\xC5\xD1\x21\xE3\xDA\x24\x3F\x48\x2B\xFB\x9F\x2E\xA1\x94\xE7\x2C\x1C\x93\xD1\xBF\x1B\x01\x87\x53\x99\xCE\xA7\xF5\x0A\x21\x76\x77\xFF\xA9\xB7\xC6\x73\x94\x4F\x46\xF7\x10\x49\x37\xFA\xA8\x59\x49\x5D\x6A\x81\x07\x56\xF2\x8A\xF9\x06\xD0\xF7\x70\x22\x4D\xB4\xB7\x41\xB9\x32\xB8\xB1\xF0\xB1\xC3\x9C\x3F\x70\xFD\x53\xDD\x81\xAA\xD8\x63\x78\xF6\xD8\x53\x6E\xA1\xAC\x6A\x84\x24\x72\x54\x86\xC6\xD2\xB2\xCA\x1C\x0E\x79\x81\xD6\xB5\x70\x62\x08\x01\x2E\x4E\x4F\x0E\xD5\x11\xAF\xA9\xAF\xE5\x9A\xBF\xDC\xCC\x87\x6D\x26\xE4\xC9\x57\xA2\xFB\x96\xF9\xCC\xE1\x3F\x53\x8C\x6C\x4C\x7E\x9B\x53\x08\x0B\x6C\x17\xFB\x67\xC8\xC2\xAD\xB1\xCD\x80\xB4\x97\xDC\x76\x01\x16\x15\xE9\x6A\xD7\xA4\xE1\x78\x47\xCE\x86\xD5\xFB\x31\xF3\xFA\x31\xBE\x34\xAA\x28\xFB\x70\x4C\x1D\x49\xC7\xAF\x2C\x9D\x6D\x66\xA6\xB6\x8D\x64\x7E\xB5\x20\x6A\x9D\x3B\x81\xB6\x8F\x40\x00\x67\x4B\x89\x86\xB8\xCC\x65\xFE\x15\x53\xE9\x04\xC1\xD6\x5F\x1D\x44\xD7\x0A\x2F\x27\x9A\x46\x7D\xA1\x0D\x75\xAD\x54\x86\x15\xDC\x49\x3B\xF1\x96\xCE\x0F\x9B\xA0\xEC\xA3\x7A\x5D\xBE\xD5\x2A\x75\x42\xE5\x7B\xDE\xA5\xB6\xAA\xAF\x28\xAC\xAC\x90\xAC\x38\xB7\xD5\x68\x35\x26\x7A\xDC\xF7\x3B\xF3\xFD\x45\x9B\xD1\xBB\x43\x78\x6E\x6F\xF1\x42\x54\x6A\x98\xF0\x0D\xAD\x97\xE9\x52\x5E\xE9\xD5\x6A\x72\xDE\x6A\xF7\x1B\x60\x14\xF4\xA5\xE4\xB6\x71\x67\xAA\x1F\xEA\xE2\x4D\xC1\x42\x40\xFE\x67\x46\x17\x38\x2F\x47\x3F\x71\x9C\xAE\xE5\x21\xCA\x61\x2D\x6D\x07\xA8\x84\x7C\x2D\xEE\x51\x25\xF1\x63\x90\x9E\xFD\xE1\x57\x88\x6B\xEF\x8A\x23\x6D\xB1\xE6\xBD\x3F\xAD\xD1\x3D\x96\x0B\x85\x8D\xCD\x6B\x27\xBB\xB7\x05\x9B\xEC\xBB\x91\xA9\x0A\x07\x12\x02\x97\x4E\x20\x90\xF0\xFF\x0D\x1E\xE2\x41\x3B\xD3\x40\x3A\xE7\x8D\x5D\xDA\x66\xE4\x02\xB0\x07\x52\x98\x5C\x0E\x8E\x33\x9C\xC2\xA6\x95\xFB\x55\x19\x6E\x4C\x8E\xAE\x4B\x0F\xBD\xC1\x38\x4D\x5E\x8F\x84\x1D\x66\xCD\xC5\x60\x96\xB4\x52\x5A\x05\x89\x8E\x95\x7A\x98\xC1\x91\x3C\x95\x23\xB2\x0E\xF4\x79\xB4\xC9\x7C\xC1\x4A\x21\x02\x03\x01\x00\x01\xA3\x6A\x30\x68\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xCC\xCC\xEF\xCC\x29\x60\xA4\x3B\xB1\x92\xB6\x3C\xFA\x32\x62\x8F\xAC\x25\x15\x3B\x30\x0C\x06\x03\x55\x1D\x13\x04\x05\x30\x03\x01\x01\xFF\x30\x39\x06\x04\x67\x2A\x07\x00\x04\x31\x30\x2F\x30\x2D\x02\x01\x00\x30\x09\x06\x05\x2B\x0E\x03\x02\x1A\x05\x00\x30\x07\x06\x05\x67\x2A\x03\x00\x00\x04\x14\x03\x9B\xF0\x22\x13\xFF\x95\x28\x36\xD3\xDC\x9E\xC0\x32\xFB\x31\x3A\x8A\x51\x65\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x02\x01\x00\x40\x80\x4A\xFA\x26\xC9\xCE\x5E\x30\xDD\x4F\x86\x74\x76\x58\xF5\xAE\xB3\x83\x33\x78\xA4\x7A\x74\x17\x19\x4E\xE9\x52\xB5\xB9\xE0\x0A\x74\x62\xAA\x68\xCA\x78\xA0\x4C\x9A\x8E\x2C\x23\x2E\xD5\x6A\x12\x24\xBF\xD4\x68\xD3\x8A\xD0\xD8\x9C\x9F\xB4\x1F\x0C\xDE\x38\x7E\x57\x38\xFC\x8D\xE2\x4F\x5E\x0C\x9F\xAB\x3B\xD2\xFF\x75\x97\xCB\xA4\xE3\x67\x08\xFF\xE5\xC0\x16\xB5\x48\x01\x7D\xE9\xF9\x0A\xFF\x1B\xE5\x6A\x69\xBF\x78\x21\xA8\xC2\xA7\x23\xA9\x86\xAB\x76\x56\xE8\x0E\x0C\xF6\x13\xDD\x2A\x66\x8A\x64\x49\x3D\x1A\x18\x87\x90\x04\x9F\x42\x52\xB7\x4F\xCB\xFE\x47\x41\x76\x35\xEF\xFF\x00\x76\x36\x45\x32\x9B\xC6\x46\x85\x5D\xE2\x24\xB0\x1E\xE3\x48\x96\x98\x57\x47\x94\x55\x7A\x0F\x41\xB1\x44\x24\xF3\xC1\xFE\x1A\x6B\xBF\x88\xFD\xC1\xA6\xDA\x93\x60\x5E\x81\x4A\x99\x20\x9C\x48\x66\x19\xB5\x00\x79\x54\x0F\xB8\x2C\x2F\x4B\xBC\xA9\x5D\x5B\x60\x7F\x8C\x87\xA5\xE0\x52\x63\x2A\xBE\xD8\x3B\x85\x40\x15\xFE\x1E\xB6\x65\x3F\xC5\x4B\xDA\x7E\xB5\x7A\x35\x29\xA3\x2E\x7A\x98\x60\x22\xA3\xF4\x7D\x27\x4E\x2D\xEA\xB4\x74\x3C\xE9\x0F\xA4\x33\x0F\x10\x11\xBC\x13\x01\xD6\xE5\x0E\xD3\xBF\xB5\x12\xA2\xE1\x45\x23\xC0\xCC\x08\x6E\x61\xB7\x89\xAB\x83\xE3\x24\x1E\xE6\x5D\x07\xE7\x1F\x20\x3E\xCF\x67\xC8\xE7\xAC\x30\x6D\x27\x4B\x68\x6E\x4B\x2A\x5C\x02\x08\x34\xDB\xF8\x76\xE4\x67\xA3\x26\x9C\x3F\xA2\x32\xC2\x4A\xC5\x81\x18\x31\x10\x56\xAA\x84\xEF\x2D\x0A\xFF\xB8\x1F\x77\xD2\xBF\xA5\x58\xA0\x62\xE4\xD7\x4B\x91\x75\x8D\x89\x80\x98\x7E\x6D\xCB\x53\x4E\x5E\xAF\xF6\xB2\x97\x85\x97\xB9\xDA\x55\x06\xB9\x24\xEE\xD7\xC6\x38\x1E\x63\x1B\x12\x3B\x95\xE1\x58\xAC\xF2\xDF\x84\xD5\x5F\x99\x2F\x0D\x55\x5B\xE6\x38\xDB\x2E\x3F\x72\xE9\x48\x85\xCB\xBB\x29\x13\x8F\x1E\x38\x55\xB9\xF3\xB2\xC4\x30\x99\x23\x4E\x5D\xF2\x48\xA1\x12\x0C\xDC\x12\x90\x09\x90\x54\x91\x03\x3C\x47\xE5\xD5\xC9\x65\xE0\xB7\x4B\x7D\xEC\x47\xD3\xB3\x0B\x3E\xAD\x9E\xD0\x74\x00\x0E\xEB\xBD\x51\xAD\xC0\xDE\x2C\xC0\xC3\x6A\xFE\xEF\xDC\x0B\xA7\xFA\x46\xDF\x60\xDB\x9C\xA6\x59\x50\x75\x23\x69\x73\x93\xB2\xF9\xFC\x02\xD3\x47\xE6\x71\xCE\x10\x02\xEE\x27\x8C\x84\xFF\xAC\x45\x0D\x13\x5C\x83\x32\xE0\x25\xA5\x86\x2C\x7C\xF4\x12", - ["emailAddress=ca@firmaprofesional.com,CN=Autoridad de Certificacion Firmaprofesional CIF A62634068,L=C/ Muntaner 244 Barcelona,C=ES"] = "\x30\x82\x04\x57\x30\x82\x03\x3F\xA0\x03\x02\x01\x02\x02\x01\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x81\x9D\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x45\x53\x31\x22\x30\x20\x06\x03\x55\x04\x07\x13\x19\x43\x2F\x20\x4D\x75\x6E\x74\x61\x6E\x65\x72\x20\x32\x34\x34\x20\x42\x61\x72\x63\x65\x6C\x6F\x6E\x61\x31\x42\x30\x40\x06\x03\x55\x04\x03\x13\x39\x41\x75\x74\x6F\x72\x69\x64\x61\x64\x20\x64\x65\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x63\x69\x6F\x6E\x20\x46\x69\x72\x6D\x61\x70\x72\x6F\x66\x65\x73\x69\x6F\x6E\x61\x6C\x20\x43\x49\x46\x20\x41\x36\x32\x36\x33\x34\x30\x36\x38\x31\x26\x30\x24\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x17\x63\x61\x40\x66\x69\x72\x6D\x61\x70\x72\x6F\x66\x65\x73\x69\x6F\x6E\x61\x6C\x2E\x63\x6F\x6D\x30\x1E\x17\x0D\x30\x31\x31\x30\x32\x34\x32\x32\x30\x30\x30\x30\x5A\x17\x0D\x31\x33\x31\x30\x32\x34\x32\x32\x30\x30\x30\x30\x5A\x30\x81\x9D\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x45\x53\x31\x22\x30\x20\x06\x03\x55\x04\x07\x13\x19\x43\x2F\x20\x4D\x75\x6E\x74\x61\x6E\x65\x72\x20\x32\x34\x34\x20\x42\x61\x72\x63\x65\x6C\x6F\x6E\x61\x31\x42\x30\x40\x06\x03\x55\x04\x03\x13\x39\x41\x75\x74\x6F\x72\x69\x64\x61\x64\x20\x64\x65\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x63\x69\x6F\x6E\x20\x46\x69\x72\x6D\x61\x70\x72\x6F\x66\x65\x73\x69\x6F\x6E\x61\x6C\x20\x43\x49\x46\x20\x41\x36\x32\x36\x33\x34\x30\x36\x38\x31\x26\x30\x24\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01\x16\x17\x63\x61\x40\x66\x69\x72\x6D\x61\x70\x72\x6F\x66\x65\x73\x69\x6F\x6E\x61\x6C\x2E\x63\x6F\x6D\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xE7\x23\x03\x6F\x6F\x23\xA5\x5E\x78\xCE\x95\x2C\xED\x94\x1E\x6E\x0A\x9E\x01\xC7\xEA\x30\xD1\x2C\x9D\xDD\x37\xE8\x9B\x98\x79\x56\xD3\xFC\x73\xDF\xD0\x8A\xDE\x55\x8F\x51\xF9\x5A\xEA\xDE\xB5\x70\xC4\xED\xA4\xED\xFF\xA3\x0D\x6E\x0F\x64\x50\x31\xAF\x01\x27\x58\xAE\xFE\x6C\xA7\x4A\x2F\x17\x2D\xD3\x73\xD5\x13\x1C\x8F\x59\xA5\x34\x2C\x1D\x54\x04\x45\xCD\x68\xB8\xA0\xC0\x03\xA5\xCF\x85\x42\x47\x95\x28\x5B\xCF\xEF\x80\x6C\xE0\x90\x97\x8A\x01\x3C\x1D\xF3\x87\x10\x30\x26\x48\x7D\xD7\xFC\xE9\x9D\x91\x71\xFF\x41\x9A\xA9\x40\xB5\x37\x9C\x29\x20\x4F\x1F\x52\xE3\xA0\x7D\x13\x6D\x54\xB7\x0A\xDE\xE9\x6A\x4E\x07\xAC\xAC\x19\x5F\xDC\x7E\x62\x74\xF6\xB2\x05\x00\xBA\x85\xA0\xFD\x1D\x38\x6E\xCB\x5A\xBB\x86\xBC\x94\x67\x33\x35\x83\x2C\x1F\x23\xCD\xF8\xC8\x91\x71\xCC\x97\x8B\xEF\xAE\x0F\xDC\x29\x03\x1B\xC0\x39\xEB\x70\xED\xC1\x6E\x0E\xD8\x67\x0B\x89\xA9\xBC\x35\xE4\xEF\xB6\x34\xB4\xA5\xB6\xC4\x2D\xA5\xBE\xD0\xC3\x94\x24\x48\xDB\xDF\x96\xD3\x00\xB5\x66\x1A\x8B\x66\x05\x0F\xDD\x3F\x3F\xCB\x3F\xAA\x5E\x9A\x4A\xF8\xB4\x4A\xEF\x95\x37\x1B\x02\x03\x01\x00\x01\xA3\x81\x9F\x30\x81\x9C\x30\x2A\x06\x03\x55\x1D\x11\x04\x23\x30\x21\x86\x1F\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x66\x69\x72\x6D\x61\x70\x72\x6F\x66\x65\x73\x69\x6F\x6E\x61\x6C\x2E\x63\x6F\x6D\x30\x12\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x08\x30\x06\x01\x01\xFF\x02\x01\x01\x30\x2B\x06\x03\x55\x1D\x10\x04\x24\x30\x22\x80\x0F\x32\x30\x30\x31\x31\x30\x32\x34\x32\x32\x30\x30\x30\x30\x5A\x81\x0F\x32\x30\x31\x33\x31\x30\x32\x34\x32\x32\x30\x30\x30\x30\x5A\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x33\x0B\xA0\x66\xD1\xEA\xDA\xCE\xDE\x62\x93\x04\x28\x52\xB5\x14\x7F\x38\x68\xB7\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x47\x73\xFE\x8D\x27\x54\xF0\xF5\xD4\x77\x9C\x27\x79\x57\x57\xB7\x15\x56\xEC\xC7\xD8\x58\xB7\x01\x02\xF4\x33\xED\x93\x50\x88\x9E\x7C\x46\xB1\xBD\x3F\x14\x6F\xF1\xB3\x47\x48\x8B\x8C\x97\x06\xD7\xEA\x7E\xA3\x5C\x2A\xBB\x4D\x2F\x47\xE2\xF8\x39\x06\xC9\x9C\x2E\x31\x1A\x03\x78\xF4\xBC\x38\xC6\x22\x8B\x33\x31\xF0\x16\x04\x04\x7D\xF9\x76\xE4\x4B\xD7\xC0\xE6\x83\xEC\x59\xCC\x3F\xDE\xFF\x4F\x6B\xB7\x67\x7E\xA6\x86\x81\x32\x23\x03\x9D\xC8\xF7\x5F\xC1\x4A\x60\xA5\x92\xA9\xB1\xA4\xA0\x60\xC3\x78\x87\xB3\x22\xF3\x2A\xEB\x5B\xA9\xED\x05\xAB\x37\x0F\xB1\xE2\xD3\x95\x76\x63\x56\x74\x8C\x58\x72\x1B\x37\xE5\x64\xA1\xBE\x4D\x0C\x93\x98\x0C\x97\xF6\x87\x6D\xB3\x3F\xE7\xCB\x80\xA6\xED\x88\xC7\x5F\x50\x62\x02\xE8\x99\x74\x16\xD0\xE6\xB4\x39\xF1\x27\xCB\xC8\x40\xD6\xE3\x86\x10\xA9\x23\x12\x92\xE0\x69\x41\x63\xA7\xAF\x25\x0B\xC0\xC5\x92\xCB\x1E\x98\xA3\x5A\xBA\xC5\x33\x0F\xA0\x97\x01\xDD\x7F\xE0\x7B\xD6\x06\x54\xCF\xA1\xE2\x4D\x38\xEB\x4B\x50\xB5\xCB\x26\xF4\xCA\xDA\x70\x4A\x6A\xA1\xE2\x79\xAA\xE1\xA7\x33\xF6\xFD\x4A\x1F\xF6\xD9\x60", - ["CN=Wells Fargo Root Certificate Authority,OU=Wells Fargo Certification Authority,O=Wells Fargo,C=US"] = "\x30\x82\x03\xE5\x30\x82\x02\xCD\xA0\x03\x02\x01\x02\x02\x04\x39\xE4\x97\x9E\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x81\x82\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x14\x30\x12\x06\x03\x55\x04\x0A\x13\x0B\x57\x65\x6C\x6C\x73\x20\x46\x61\x72\x67\x6F\x31\x2C\x30\x2A\x06\x03\x55\x04\x0B\x13\x23\x57\x65\x6C\x6C\x73\x20\x46\x61\x72\x67\x6F\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x31\x2F\x30\x2D\x06\x03\x55\x04\x03\x13\x26\x57\x65\x6C\x6C\x73\x20\x46\x61\x72\x67\x6F\x20\x52\x6F\x6F\x74\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x1E\x17\x0D\x30\x30\x31\x30\x31\x31\x31\x36\x34\x31\x32\x38\x5A\x17\x0D\x32\x31\x30\x31\x31\x34\x31\x36\x34\x31\x32\x38\x5A\x30\x81\x82\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x14\x30\x12\x06\x03\x55\x04\x0A\x13\x0B\x57\x65\x6C\x6C\x73\x20\x46\x61\x72\x67\x6F\x31\x2C\x30\x2A\x06\x03\x55\x04\x0B\x13\x23\x57\x65\x6C\x6C\x73\x20\x46\x61\x72\x67\x6F\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x31\x2F\x30\x2D\x06\x03\x55\x04\x03\x13\x26\x57\x65\x6C\x6C\x73\x20\x46\x61\x72\x67\x6F\x20\x52\x6F\x6F\x74\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xD5\xA8\x33\x3B\x26\xF9\x34\xFF\xCD\x9B\x7E\xE5\x04\x47\xCE\x00\xE2\x7D\x77\xE7\x31\xC2\x2E\x27\xA5\x4D\x68\xB9\x31\xBA\x8D\x43\x59\x97\xC7\x73\xAA\x7F\x3D\x5C\x40\x9E\x05\xE5\xA1\xE2\x89\xD9\x4C\xB8\x3F\x9B\xF9\x0C\xB4\xC8\x62\x19\x2C\x45\xAE\x91\x1E\x73\x71\x41\xC4\x4B\x13\xFD\x70\xC2\x25\xAC\x22\xF5\x75\x0B\xB7\x53\xE4\xA5\x2B\xDD\xCE\xBD\x1C\x3A\x7A\xC3\xF7\x13\x8F\x26\x54\x9C\x16\x6B\x6B\xAF\xFB\xD8\x96\xB1\x60\x9A\x48\xE0\x25\x22\x24\x79\x34\xCE\x0E\x26\x00\x0B\x4E\xAB\xFD\x8B\xCE\x82\xD7\x2F\x08\x70\x68\xC1\xA8\x0A\xF9\x74\x4F\x07\xAB\xA4\xF9\xE2\x83\x7E\x27\x73\x74\x3E\xB8\xF9\x38\x42\xFC\xA5\xA8\x5B\x48\x23\xB3\xEB\xE3\x25\xB2\x80\xAE\x96\xD4\x0A\x9C\xC2\x78\x9A\xC6\x68\x18\xAE\x37\x62\x37\x5E\x51\x75\xA8\x58\x63\xC0\x51\xEE\x40\x78\x7E\xA8\xAF\x1A\xA0\xE1\xB0\x78\x9D\x50\x8C\x7B\xE7\xB3\xFC\x8E\x23\xB0\xDB\x65\x00\x70\x84\x01\x08\x00\x14\x6E\x54\x86\x9A\xBA\xCC\xF9\x37\x10\xF6\xE0\xDE\x84\x2D\x9D\xA4\x85\x37\xD3\x87\xE3\x15\xD0\xC1\x17\x90\x7E\x19\x21\x6A\x12\xA9\x76\xFD\x12\x02\xE9\x4F\x21\x5E\x17\x02\x03\x01\x00\x01\xA3\x61\x30\x5F\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x4C\x06\x03\x55\x1D\x20\x04\x45\x30\x43\x30\x41\x06\x0B\x60\x86\x48\x01\x86\xFB\x7B\x87\x07\x01\x0B\x30\x32\x30\x30\x06\x08\x2B\x06\x01\x05\x05\x07\x02\x01\x16\x24\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x77\x65\x6C\x6C\x73\x66\x61\x72\x67\x6F\x2E\x63\x6F\x6D\x2F\x63\x65\x72\x74\x70\x6F\x6C\x69\x63\x79\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\xD2\x27\xDD\x9C\x0A\x77\x2B\xBB\x22\xF2\x02\xB5\x4A\x4A\x91\xF9\xD1\x2D\xBE\xE4\xBB\x1A\x68\xEF\x0E\xA4\x00\xE9\xEE\xE7\xEF\xEE\xF6\xF9\xE5\x74\xA4\xC2\xD8\x52\x58\xC4\x74\xFB\xCE\x6B\xB5\x3B\x29\x79\x18\x5A\xEF\x9B\xED\x1F\x6B\x36\xEE\x48\x25\x25\x14\xB6\x56\xA2\x10\xE8\xEE\xA7\x7F\xD0\x3F\xA3\xD0\xC3\x5D\x26\xEE\x07\xCC\xC3\xC1\x24\x21\x87\x1E\xDF\x2A\x12\x53\x6F\x41\x16\xE7\xED\xAE\x94\xFA\x8C\x72\xFA\x13\x47\xF0\x3C\x7E\xAE\x7D\x11\x3A\x13\xEC\xED\xFA\x6F\x72\x64\x7B\x9D\x7D\x7F\x26\xFD\x7A\xFB\x25\xAD\xEA\x3E\x29\x7F\x4C\xE3\x00\x57\x32\xB0\xB3\xE9\xED\x53\x17\xD9\x8B\xB2\x14\x0E\x30\xE8\xE5\xD5\x13\xC6\x64\xAF\xC4\x00\xD5\xD8\x58\x24\xFC\xF5\x8F\xEC\xF1\xC7\x7D\xA5\xDB\x0F\x27\xD1\xC6\xF2\x40\x88\xE6\x1F\xF6\x61\xA8\xF4\x42\xC8\xB9\x37\xD3\xA9\xBE\x2C\x56\x78\xC2\x72\x9B\x59\x5D\x35\x40\x8A\xE8\x4E\x63\x1A\xB6\xE9\x20\x6A\x51\xE2\xCE\xA4\x90\xDF\x76\x70\x99\x5C\x70\x43\x4D\xB7\xB6\xA7\x19\x64\x4E\x92\xB7\xC5\x91\x3C\x7F\x48\x16\x65\x7B\x16\xFD\xCB\xFC\xFB\xD9\xD5\xD6\x4F\x21\x65\x3B\x4A\x7F\x47\xA3\xFB", ["CN=Swisscom Root CA 1,OU=Digital Certificate Services,O=Swisscom,C=ch"] = "\x30\x82\x05\xD9\x30\x82\x03\xC1\xA0\x03\x02\x01\x02\x02\x10\x5C\x0B\x85\x5C\x0B\xE7\x59\x41\xDF\x57\xCC\x3F\x7F\x9D\xA8\x36\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x64\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x63\x68\x31\x11\x30\x0F\x06\x03\x55\x04\x0A\x13\x08\x53\x77\x69\x73\x73\x63\x6F\x6D\x31\x25\x30\x23\x06\x03\x55\x04\x0B\x13\x1C\x44\x69\x67\x69\x74\x61\x6C\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x53\x65\x72\x76\x69\x63\x65\x73\x31\x1B\x30\x19\x06\x03\x55\x04\x03\x13\x12\x53\x77\x69\x73\x73\x63\x6F\x6D\x20\x52\x6F\x6F\x74\x20\x43\x41\x20\x31\x30\x1E\x17\x0D\x30\x35\x30\x38\x31\x38\x31\x32\x30\x36\x32\x30\x5A\x17\x0D\x32\x35\x30\x38\x31\x38\x32\x32\x30\x36\x32\x30\x5A\x30\x64\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x63\x68\x31\x11\x30\x0F\x06\x03\x55\x04\x0A\x13\x08\x53\x77\x69\x73\x73\x63\x6F\x6D\x31\x25\x30\x23\x06\x03\x55\x04\x0B\x13\x1C\x44\x69\x67\x69\x74\x61\x6C\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x53\x65\x72\x76\x69\x63\x65\x73\x31\x1B\x30\x19\x06\x03\x55\x04\x03\x13\x12\x53\x77\x69\x73\x73\x63\x6F\x6D\x20\x52\x6F\x6F\x74\x20\x43\x41\x20\x31\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\xD0\xB9\xB0\xA8\x0C\xD9\xBB\x3F\x21\xF8\x1B\xD5\x33\x93\x80\x16\x65\x20\x75\xB2\x3D\x9B\x60\x6D\x46\xC8\x8C\x31\x6F\x17\xC3\xFA\x9A\x6C\x56\xED\x3C\xC5\x91\x57\xC3\xCD\xAB\x96\x49\x90\x2A\x19\x4B\x1E\xA3\x6D\x57\xDD\xF1\x2B\x62\x28\x75\x45\x5E\xAA\xD6\x5B\xFA\x0B\x25\xD8\xA1\x16\xF9\x1C\xC4\x2E\xE6\x95\x2A\x67\xCC\xD0\x29\x6E\x3C\x85\x34\x38\x61\x49\xB1\x00\x9F\xD6\x3A\x71\x5F\x4D\x6D\xCE\x5F\xB9\xA9\xE4\x89\x7F\x6A\x52\xFA\xCA\x9B\xF2\xDC\xA9\xF9\x9D\x99\x47\x3F\x4E\x29\x5F\xB4\xA6\x8D\x5D\x7B\x0B\x99\x11\x03\x03\xFE\xE7\xDB\xDB\xA3\xFF\x1D\xA5\xCD\x90\x1E\x01\x1F\x35\xB0\x7F\x00\xDB\x90\x6F\xC6\x7E\x7B\xD1\xEE\x7A\x7A\xA7\xAA\x0C\x57\x6F\xA4\x6D\xC5\x13\x3B\xB0\xA5\xD9\xED\x32\x1C\xB4\x5E\x67\x8B\x54\xDC\x73\x87\xE5\xD3\x17\x7C\x66\x50\x72\x5D\xD4\x1A\x58\xC1\xD9\xCF\xD8\x89\x02\x6F\xA7\x49\xB4\x36\x5D\xD0\xA4\xDE\x07\x2C\xB6\x75\xB7\x28\x91\xD6\x97\xBE\x28\xF5\x98\x1E\xEA\x5B\x26\xC9\xBD\xB0\x97\x73\xDA\xAE\x91\x26\xEB\x68\xC1\xF9\x39\x15\xD6\x67\x4B\x0A\x6D\x4F\xCB\xCF\xB0\xE4\x42\x71\x8C\x53\x79\xE7\xEE\xE1\xDB\x1D\xA0\x6E\x1D\x8C\x1A\x77\x35\x5C\x16\x1E\x2B\x53\x1F\x34\x8B\xD1\x6C\xFC\xF2\x67\x07\x7A\xF5\xAD\xED\xD6\x9A\xAB\xA1\xB1\x4B\xE1\xCC\x37\x5F\xFD\x7F\xCD\x4D\xAE\xB8\x1F\x9C\x43\xF9\x2A\x58\x55\x43\x45\xBC\x96\xCD\x70\x0E\xFC\xC9\xE3\x66\xBA\x4E\x8D\x3B\x81\xCB\x15\x64\x7B\xB9\x94\xE8\x5D\x33\x52\x85\x71\x2E\x4F\x8E\xA2\x06\x11\x51\xC9\xE3\xCB\xA1\x6E\x31\x08\x64\x0C\xC2\xD2\x3C\xF5\x36\xE8\xD7\xD0\x0E\x78\x23\x20\x91\xC9\x24\x2A\x65\x29\x5B\x22\xF7\x21\xCE\x83\x5E\xA4\xF3\xDE\x4B\xD3\x68\x8F\x46\x75\x5C\x83\x09\x6E\x29\x6B\xC4\x70\x8C\xF5\x9D\xD7\x20\x2F\xFF\x46\xD2\x2B\x38\xC2\x2F\x75\x1C\x3D\x7E\xDA\xA5\xEF\x1E\x60\x85\x69\x42\xD3\xCC\xF8\x63\xFE\x1E\x43\x39\x85\xA6\xB6\x63\x41\x10\xB3\x73\x1E\xBC\xD3\xFA\xCA\x7D\x16\x47\xE2\xA7\xD5\xD0\xA3\x8A\x0A\x08\x96\x62\x56\x6E\x34\xDB\xD9\x02\xB9\x30\x75\xE3\x04\xD2\xE7\x8F\xC2\xB0\x11\x40\x0A\xAC\xD5\x71\x02\x62\x8B\x31\xBE\xDD\xC6\x23\x58\x31\x42\x43\x2D\x74\xF9\xC6\x9E\xA6\x8A\x0F\xE9\xFE\xBF\x83\xE6\x43\x57\x24\xBA\xEF\x46\x34\xAA\xD7\x12\x01\x38\xED\x02\x03\x01\x00\x01\xA3\x81\x86\x30\x81\x83\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x86\x30\x1D\x06\x03\x55\x1D\x21\x04\x16\x30\x14\x30\x12\x06\x07\x60\x85\x74\x01\x53\x00\x01\x06\x07\x60\x85\x74\x01\x53\x00\x01\x30\x12\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x08\x30\x06\x01\x01\xFF\x02\x01\x07\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\x03\x25\x2F\xDE\x6F\x82\x01\x3A\x5C\x2C\xDC\x2B\xA1\x69\xB5\x67\xD4\x8C\xD3\xFD\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x03\x25\x2F\xDE\x6F\x82\x01\x3A\x5C\x2C\xDC\x2B\xA1\x69\xB5\x67\xD4\x8C\xD3\xFD\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x02\x01\x00\x35\x10\xCB\xEC\xA6\x04\x0D\x0D\x0F\xCD\xC0\xDB\xAB\xA8\xF2\x88\x97\x0C\xDF\x93\x2F\x4D\x7C\x40\x56\x31\x7A\xEB\xA4\x0F\x60\xCD\x7A\xF3\xBE\xC3\x27\x8E\x03\x3E\xA4\xDD\x12\xEF\x7E\x1E\x74\x06\x3C\x3F\x31\xF2\x1C\x7B\x91\x31\x21\xB4\xF0\xD0\x6C\x97\xD4\xE9\x97\xB2\x24\x56\x1E\x56\xC3\x35\xBD\x88\x05\x0F\x5B\x10\x1A\x64\xE1\xC7\x82\x30\xF9\x32\xAD\x9E\x50\x2C\xE7\x78\x05\xD0\x31\xB1\x5A\x98\x8A\x75\x4E\x90\x5C\x6A\x14\x2A\xE0\x52\x47\x82\x60\xE6\x1E\xDA\x81\xB1\xFB\x14\x0B\x5A\xF1\x9F\xD2\x95\xBA\x3E\xD0\x1B\xD6\x15\x1D\xA3\xBE\x86\xD5\xDB\x0F\xC0\x49\x64\xBB\x2E\x50\x19\x4B\xD2\x24\xF8\xDD\x1E\x07\x56\xD0\x38\xA0\x95\x70\x20\x76\x8C\xD7\xDD\x1E\xDE\x9F\x71\xC4\x23\xEF\x83\x13\x5C\xA3\x24\x15\x4D\x29\x40\x3C\x6A\xC4\xA9\xD8\xB7\xA6\x44\xA5\x0D\xF4\xE0\x9D\x77\x1E\x40\x70\x26\xFC\xDA\xD9\x36\xE4\x79\xE4\xB5\x3F\xBC\x9B\x65\xBE\xBB\x11\x96\xCF\xDB\xC6\x28\x39\x3A\x08\xCE\x47\x5B\x53\x5A\xC5\x99\xFE\x5D\xA9\xDD\xEF\x4C\xD4\xC6\xA5\xAD\x02\xE6\x8C\x07\x12\x1E\x6F\x03\xD1\x6F\xA0\xA3\xF3\x29\xBD\x12\xC7\x50\xA2\xB0\x7F\x88\xA9\x99\x77\x9A\xB1\xC0\xA5\x39\x2E\x5C\x7C\x69\xE2\x2C\xB0\xEA\x37\x6A\xA4\xE1\x5A\xE1\xF5\x50\xE5\x83\xEF\xA5\xBB\x2A\x88\xE7\x8C\xDB\xFD\x6D\x5E\x97\x19\xA8\x7E\x66\x75\x6B\x71\xEA\xBF\xB1\xC7\x6F\xA0\xF4\x8E\xA4\xEC\x34\x51\x5B\x8C\x26\x03\x70\xA1\x77\xD5\x01\x12\x57\x00\x35\xDB\x23\xDE\x0E\x8A\x28\x99\xFD\xB1\x10\x6F\x4B\xFF\x38\x2D\x60\x4E\x2C\x9C\xEB\x67\xB5\xAD\x49\xEE\x4B\x1F\xAC\xAF\xFB\x0D\x90\x5A\x66\x60\x70\x5D\xAA\xCD\x78\xD4\x24\xEE\xC8\x41\xA0\x93\x01\x92\x9C\x6A\x9E\xFC\xB9\x24\xC5\xB3\x15\x82\x7E\xBE\xAE\x95\x2B\xEB\xB1\xC0\xDA\xE3\x01\x60\x0B\x5E\x69\xAC\x84\x56\x61\xBE\x71\x17\xFE\x1D\x13\x0F\xFE\xC6\x87\x45\xE9\xFE\x32\xA0\x1A\x0D\x13\xA4\x94\x55\x71\xA5\x16\x8B\xBA\xCA\x89\xB0\xB2\xC7\xFC\x8F\xD8\x54\xB5\x93\x62\x9D\xCE\xCF\x59\xFB\x3D\x18\xCE\x2A\xCB\x35\x15\x82\x5D\xFF\x54\x22\x5B\x71\x52\xFB\xB7\xC9\xFE\x60\x9B\x00\x41\x64\xF0\xAA\x2A\xEC\xB6\x42\x43\xCE\x89\x66\x81\xC8\x8B\x9F\x39\x54\x03\x25\xD3\x16\x35\x8E\x84\xD0\x5F\xFA\x30\x1A\xF5\x9A\x6C\xF4\x0E\x53\xF9\x3A\x5B\xD1\x1C", ["CN=DigiCert Assured ID Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US"] = "\x30\x82\x03\xB7\x30\x82\x02\x9F\xA0\x03\x02\x01\x02\x02\x10\x0C\xE7\xE0\xE5\x17\xD8\x46\xFE\x8F\xE5\x60\xFC\x1B\xF0\x30\x39\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x65\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x15\x30\x13\x06\x03\x55\x04\x0A\x13\x0C\x44\x69\x67\x69\x43\x65\x72\x74\x20\x49\x6E\x63\x31\x19\x30\x17\x06\x03\x55\x04\x0B\x13\x10\x77\x77\x77\x2E\x64\x69\x67\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x31\x24\x30\x22\x06\x03\x55\x04\x03\x13\x1B\x44\x69\x67\x69\x43\x65\x72\x74\x20\x41\x73\x73\x75\x72\x65\x64\x20\x49\x44\x20\x52\x6F\x6F\x74\x20\x43\x41\x30\x1E\x17\x0D\x30\x36\x31\x31\x31\x30\x30\x30\x30\x30\x30\x30\x5A\x17\x0D\x33\x31\x31\x31\x31\x30\x30\x30\x30\x30\x30\x30\x5A\x30\x65\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x15\x30\x13\x06\x03\x55\x04\x0A\x13\x0C\x44\x69\x67\x69\x43\x65\x72\x74\x20\x49\x6E\x63\x31\x19\x30\x17\x06\x03\x55\x04\x0B\x13\x10\x77\x77\x77\x2E\x64\x69\x67\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x31\x24\x30\x22\x06\x03\x55\x04\x03\x13\x1B\x44\x69\x67\x69\x43\x65\x72\x74\x20\x41\x73\x73\x75\x72\x65\x64\x20\x49\x44\x20\x52\x6F\x6F\x74\x20\x43\x41\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xAD\x0E\x15\xCE\xE4\x43\x80\x5C\xB1\x87\xF3\xB7\x60\xF9\x71\x12\xA5\xAE\xDC\x26\x94\x88\xAA\xF4\xCE\xF5\x20\x39\x28\x58\x60\x0C\xF8\x80\xDA\xA9\x15\x95\x32\x61\x3C\xB5\xB1\x28\x84\x8A\x8A\xDC\x9F\x0A\x0C\x83\x17\x7A\x8F\x90\xAC\x8A\xE7\x79\x53\x5C\x31\x84\x2A\xF6\x0F\x98\x32\x36\x76\xCC\xDE\xDD\x3C\xA8\xA2\xEF\x6A\xFB\x21\xF2\x52\x61\xDF\x9F\x20\xD7\x1F\xE2\xB1\xD9\xFE\x18\x64\xD2\x12\x5B\x5F\xF9\x58\x18\x35\xBC\x47\xCD\xA1\x36\xF9\x6B\x7F\xD4\xB0\x38\x3E\xC1\x1B\xC3\x8C\x33\xD9\xD8\x2F\x18\xFE\x28\x0F\xB3\xA7\x83\xD6\xC3\x6E\x44\xC0\x61\x35\x96\x16\xFE\x59\x9C\x8B\x76\x6D\xD7\xF1\xA2\x4B\x0D\x2B\xFF\x0B\x72\xDA\x9E\x60\xD0\x8E\x90\x35\xC6\x78\x55\x87\x20\xA1\xCF\xE5\x6D\x0A\xC8\x49\x7C\x31\x98\x33\x6C\x22\xE9\x87\xD0\x32\x5A\xA2\xBA\x13\x82\x11\xED\x39\x17\x9D\x99\x3A\x72\xA1\xE6\xFA\xA4\xD9\xD5\x17\x31\x75\xAE\x85\x7D\x22\xAE\x3F\x01\x46\x86\xF6\x28\x79\xC8\xB1\xDA\xE4\x57\x17\xC4\x7E\x1C\x0E\xB0\xB4\x92\xA6\x56\xB3\xBD\xB2\x97\xED\xAA\xA7\xF0\xB7\xC5\xA8\x3F\x95\x16\xD0\xFF\xA1\x96\xEB\x08\x5F\x18\x77\x4F\x02\x03\x01\x00\x01\xA3\x63\x30\x61\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x86\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x45\xEB\xA2\xAF\xF4\x92\xCB\x82\x31\x2D\x51\x8B\xA7\xA7\x21\x9D\xF3\x6D\xC8\x0F\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\x45\xEB\xA2\xAF\xF4\x92\xCB\x82\x31\x2D\x51\x8B\xA7\xA7\x21\x9D\xF3\x6D\xC8\x0F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\xA2\x0E\xBC\xDF\xE2\xED\xF0\xE3\x72\x73\x7A\x64\x94\xBF\xF7\x72\x66\xD8\x32\xE4\x42\x75\x62\xAE\x87\xEB\xF2\xD5\xD9\xDE\x56\xB3\x9F\xCC\xCE\x14\x28\xB9\x0D\x97\x60\x5C\x12\x4C\x58\xE4\xD3\x3D\x83\x49\x45\x58\x97\x35\x69\x1A\xA8\x47\xEA\x56\xC6\x79\xAB\x12\xD8\x67\x81\x84\xDF\x7F\x09\x3C\x94\xE6\xB8\x26\x2C\x20\xBD\x3D\xB3\x28\x89\xF7\x5F\xFF\x22\xE2\x97\x84\x1F\xE9\x65\xEF\x87\xE0\xDF\xC1\x67\x49\xB3\x5D\xEB\xB2\x09\x2A\xEB\x26\xED\x78\xBE\x7D\x3F\x2B\xF3\xB7\x26\x35\x6D\x5F\x89\x01\xB6\x49\x5B\x9F\x01\x05\x9B\xAB\x3D\x25\xC1\xCC\xB6\x7F\xC2\xF1\x6F\x86\xC6\xFA\x64\x68\xEB\x81\x2D\x94\xEB\x42\xB7\xFA\x8C\x1E\xDD\x62\xF1\xBE\x50\x67\xB7\x6C\xBD\xF3\xF1\x1F\x6B\x0C\x36\x07\x16\x7F\x37\x7C\xA9\x5B\x6D\x7A\xF1\x12\x46\x60\x83\xD7\x27\x04\xBE\x4B\xCE\x97\xBE\xC3\x67\x2A\x68\x11\xDF\x80\xE7\x0C\x33\x66\xBF\x13\x0D\x14\x6E\xF3\x7F\x1F\x63\x10\x1E\xFA\x8D\x1B\x25\x6D\x6C\x8F\xA5\xB7\x61\x01\xB1\xD2\xA3\x26\xA1\x10\x71\x9D\xAD\xE2\xC3\xF9\xC3\x99\x51\xB7\x2B\x07\x08\xCE\x2E\xE6\x50\xB2\xA7\xFA\x0A\x45\x2F\xA2\xF0\xF2", ["CN=DigiCert Global Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US"] = "\x30\x82\x03\xAF\x30\x82\x02\x97\xA0\x03\x02\x01\x02\x02\x10\x08\x3B\xE0\x56\x90\x42\x46\xB1\xA1\x75\x6A\xC9\x59\x91\xC7\x4A\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x61\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x15\x30\x13\x06\x03\x55\x04\x0A\x13\x0C\x44\x69\x67\x69\x43\x65\x72\x74\x20\x49\x6E\x63\x31\x19\x30\x17\x06\x03\x55\x04\x0B\x13\x10\x77\x77\x77\x2E\x64\x69\x67\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x31\x20\x30\x1E\x06\x03\x55\x04\x03\x13\x17\x44\x69\x67\x69\x43\x65\x72\x74\x20\x47\x6C\x6F\x62\x61\x6C\x20\x52\x6F\x6F\x74\x20\x43\x41\x30\x1E\x17\x0D\x30\x36\x31\x31\x31\x30\x30\x30\x30\x30\x30\x30\x5A\x17\x0D\x33\x31\x31\x31\x31\x30\x30\x30\x30\x30\x30\x30\x5A\x30\x61\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x15\x30\x13\x06\x03\x55\x04\x0A\x13\x0C\x44\x69\x67\x69\x43\x65\x72\x74\x20\x49\x6E\x63\x31\x19\x30\x17\x06\x03\x55\x04\x0B\x13\x10\x77\x77\x77\x2E\x64\x69\x67\x69\x63\x65\x72\x74\x2E\x63\x6F\x6D\x31\x20\x30\x1E\x06\x03\x55\x04\x03\x13\x17\x44\x69\x67\x69\x43\x65\x72\x74\x20\x47\x6C\x6F\x62\x61\x6C\x20\x52\x6F\x6F\x74\x20\x43\x41\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xE2\x3B\xE1\x11\x72\xDE\xA8\xA4\xD3\xA3\x57\xAA\x50\xA2\x8F\x0B\x77\x90\xC9\xA2\xA5\xEE\x12\xCE\x96\x5B\x01\x09\x20\xCC\x01\x93\xA7\x4E\x30\xB7\x53\xF7\x43\xC4\x69\x00\x57\x9D\xE2\x8D\x22\xDD\x87\x06\x40\x00\x81\x09\xCE\xCE\x1B\x83\xBF\xDF\xCD\x3B\x71\x46\xE2\xD6\x66\xC7\x05\xB3\x76\x27\x16\x8F\x7B\x9E\x1E\x95\x7D\xEE\xB7\x48\xA3\x08\xDA\xD6\xAF\x7A\x0C\x39\x06\x65\x7F\x4A\x5D\x1F\xBC\x17\xF8\xAB\xBE\xEE\x28\xD7\x74\x7F\x7A\x78\x99\x59\x85\x68\x6E\x5C\x23\x32\x4B\xBF\x4E\xC0\xE8\x5A\x6D\xE3\x70\xBF\x77\x10\xBF\xFC\x01\xF6\x85\xD9\xA8\x44\x10\x58\x32\xA9\x75\x18\xD5\xD1\xA2\xBE\x47\xE2\x27\x6A\xF4\x9A\x33\xF8\x49\x08\x60\x8B\xD4\x5F\xB4\x3A\x84\xBF\xA1\xAA\x4A\x4C\x7D\x3E\xCF\x4F\x5F\x6C\x76\x5E\xA0\x4B\x37\x91\x9E\xDC\x22\xE6\x6D\xCE\x14\x1A\x8E\x6A\xCB\xFE\xCD\xB3\x14\x64\x17\xC7\x5B\x29\x9E\x32\xBF\xF2\xEE\xFA\xD3\x0B\x42\xD4\xAB\xB7\x41\x32\xDA\x0C\xD4\xEF\xF8\x81\xD5\xBB\x8D\x58\x3F\xB5\x1B\xE8\x49\x28\xA2\x70\xDA\x31\x04\xDD\xF7\xB2\x16\xF2\x4C\x0A\x4E\x07\xA8\xED\x4A\x3D\x5E\xB5\x7F\xA3\x90\xC3\xAF\x27\x02\x03\x01\x00\x01\xA3\x63\x30\x61\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x86\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x03\xDE\x50\x35\x56\xD1\x4C\xBB\x66\xF0\xA3\xE2\x1B\x1B\xC3\x97\xB2\x3D\xD1\x55\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\x03\xDE\x50\x35\x56\xD1\x4C\xBB\x66\xF0\xA3\xE2\x1B\x1B\xC3\x97\xB2\x3D\xD1\x55\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\xCB\x9C\x37\xAA\x48\x13\x12\x0A\xFA\xDD\x44\x9C\x4F\x52\xB0\xF4\xDF\xAE\x04\xF5\x79\x79\x08\xA3\x24\x18\xFC\x4B\x2B\x84\xC0\x2D\xB9\xD5\xC7\xFE\xF4\xC1\x1F\x58\xCB\xB8\x6D\x9C\x7A\x74\xE7\x98\x29\xAB\x11\xB5\xE3\x70\xA0\xA1\xCD\x4C\x88\x99\x93\x8C\x91\x70\xE2\xAB\x0F\x1C\xBE\x93\xA9\xFF\x63\xD5\xE4\x07\x60\xD3\xA3\xBF\x9D\x5B\x09\xF1\xD5\x8E\xE3\x53\xF4\x8E\x63\xFA\x3F\xA7\xDB\xB4\x66\xDF\x62\x66\xD6\xD1\x6E\x41\x8D\xF2\x2D\xB5\xEA\x77\x4A\x9F\x9D\x58\xE2\x2B\x59\xC0\x40\x23\xED\x2D\x28\x82\x45\x3E\x79\x54\x92\x26\x98\xE0\x80\x48\xA8\x37\xEF\xF0\xD6\x79\x60\x16\xDE\xAC\xE8\x0E\xCD\x6E\xAC\x44\x17\x38\x2F\x49\xDA\xE1\x45\x3E\x2A\xB9\x36\x53\xCF\x3A\x50\x06\xF7\x2E\xE8\xC4\x57\x49\x6C\x61\x21\x18\xD5\x04\xAD\x78\x3C\x2C\x3A\x80\x6B\xA7\xEB\xAF\x15\x14\xE9\xD8\x89\xC1\xB9\x38\x6C\xE2\x91\x6C\x8A\xFF\x64\xB9\x77\x25\x57\x30\xC0\x1B\x24\xA3\xE1\xDC\xE9\xDF\x47\x7C\xB5\xB4\x24\x08\x05\x30\xEC\x2D\xBD\x0B\xBF\x45\xBF\x50\xB9\xA9\xF3\xEB\x98\x01\x12\xAD\xC8\x88\xC6\x98\x34\x5F\x8D\x0A\x3C\xC6\xE9\xD5\x95\x95\x6D\xDE", @@ -158,4 +149,10 @@ redef root_certs += { ["CN=Swisscom Root EV CA 2,OU=Digital Certificate Services,O=Swisscom,C=ch"] = "\x30\x82\x05\xE0\x30\x82\x03\xC8\xA0\x03\x02\x01\x02\x02\x11\x00\xF2\xFA\x64\xE2\x74\x63\xD3\x8D\xFD\x10\x1D\x04\x1F\x76\xCA\x58\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x30\x67\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x63\x68\x31\x11\x30\x0F\x06\x03\x55\x04\x0A\x13\x08\x53\x77\x69\x73\x73\x63\x6F\x6D\x31\x25\x30\x23\x06\x03\x55\x04\x0B\x13\x1C\x44\x69\x67\x69\x74\x61\x6C\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x53\x65\x72\x76\x69\x63\x65\x73\x31\x1E\x30\x1C\x06\x03\x55\x04\x03\x13\x15\x53\x77\x69\x73\x73\x63\x6F\x6D\x20\x52\x6F\x6F\x74\x20\x45\x56\x20\x43\x41\x20\x32\x30\x1E\x17\x0D\x31\x31\x30\x36\x32\x34\x30\x39\x34\x35\x30\x38\x5A\x17\x0D\x33\x31\x30\x36\x32\x35\x30\x38\x34\x35\x30\x38\x5A\x30\x67\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x63\x68\x31\x11\x30\x0F\x06\x03\x55\x04\x0A\x13\x08\x53\x77\x69\x73\x73\x63\x6F\x6D\x31\x25\x30\x23\x06\x03\x55\x04\x0B\x13\x1C\x44\x69\x67\x69\x74\x61\x6C\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x53\x65\x72\x76\x69\x63\x65\x73\x31\x1E\x30\x1C\x06\x03\x55\x04\x03\x13\x15\x53\x77\x69\x73\x73\x63\x6F\x6D\x20\x52\x6F\x6F\x74\x20\x45\x56\x20\x43\x41\x20\x32\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\xC4\xF7\x1D\x2F\x57\xEA\x57\x6C\xF7\x70\x5D\x63\xB0\x71\x52\x09\x60\x44\x28\x33\xA3\x7A\x4E\x0A\xFA\xD8\xEA\x6C\x8B\x51\x16\x1A\x55\xAE\x54\x26\xC4\xCC\x45\x07\x41\x4F\x10\x79\x7F\x71\xD2\x7A\x4E\x3F\x38\x4E\xB3\x00\xC6\x95\xCA\x5B\xCD\xC1\x2A\x83\xD7\x27\x1F\x31\x0E\x23\x16\xB7\x25\xCB\x1C\xB4\xB9\x80\x32\x5E\x1A\x9D\x93\xF1\xE8\x3C\x60\x2C\xA7\x5E\x57\x19\x58\x51\x5E\xBC\x2C\x56\x0B\xB8\xD8\xEF\x8B\x82\xB4\x3C\xB8\xC2\x24\xA8\x13\xC7\xA0\x21\x36\x1B\x7A\x57\x29\x28\xA7\x2E\xBF\x71\x25\x90\xF3\x44\x83\x69\x50\xA4\xE4\xE1\x1B\x62\x19\x94\x09\xA3\xF3\xC3\xBC\xEF\xF4\xBD\xEC\xDB\x13\x9D\xCF\x9D\x48\x09\x52\x67\xC0\x37\x29\x11\x1E\xFB\xD2\x11\xA7\x85\x18\x74\x79\xE4\x4F\x85\x14\xEB\x52\x37\xE2\xB1\x45\xD8\xCC\x0D\x43\x7F\xAE\x13\xD2\x6B\x2B\x3F\xA7\xC2\xE2\xA8\x6D\x76\x5B\x43\x9F\xBE\xB4\x9D\xB3\x26\x86\x3B\x1F\x7F\xE5\xF2\xE8\x66\x28\x16\x25\xD0\x4B\x97\x38\xA7\xE4\xCF\x09\xD1\x36\xC3\x0B\xBE\xDA\x3B\x44\x58\x8D\xBE\xF1\x9E\x09\x6B\x3E\xF3\x32\xC7\x2B\x87\xC6\xEC\x5E\x9C\xF6\x87\x65\xAD\x33\x29\xC4\x2F\x89\xD9\xB9\xCB\xC9\x03\x9D\xFB\x6C\x94\x51\x97\x10\x1B\x86\x0B\x1A\x1B\x3F\xF6\x02\x7E\x7B\xD4\xC5\x51\x64\x28\x9D\xF5\xD3\xAC\x83\x81\x88\xD3\x74\xB4\x59\x9D\xC1\xEB\x61\x33\x5A\x45\xD1\xCB\x39\xD0\x06\x6A\x53\x60\x1D\xAF\xF6\xFB\x69\xBC\x6A\xDC\x01\xCF\xBD\xF9\x8F\xD9\xBD\x5B\xC1\x3A\x5F\x8E\xDA\x0F\x4B\xA9\x9B\x9D\x2A\x28\x6B\x1A\x0A\x7C\x3C\xAB\x22\x0B\xE5\x77\x2D\x71\xF6\x82\x35\x81\xAE\xF8\x7B\x81\xE6\xEA\xFE\xAC\xF4\x1A\x9B\x74\x5C\xE8\x8F\x24\xF6\x5D\x9D\x46\xC4\x2C\xD2\x1E\x2B\x21\x6A\x83\x27\x67\x55\x4A\xA4\xE3\xC8\x32\x97\x66\x90\x72\xDA\xE3\xD4\x64\x2E\x5F\xE3\xA1\x6A\xF6\x60\xD4\xE7\x35\xCD\xCA\xC4\x68\x8D\xD7\x71\xC8\xD3\x24\x33\x73\xB1\x6C\xF9\x6A\xE1\x28\xDB\x5F\xC6\x3D\xE8\xBE\x55\xE6\x37\x1B\xED\x24\xD9\x0F\x19\x8F\x5F\x63\x18\x58\x50\x81\x51\x65\x6F\xF2\x9F\x7E\x6A\x04\xE7\x34\x24\x71\xBA\x76\x4B\x58\x1E\x19\xBD\x15\x60\x45\xAA\x0C\x12\x40\x01\x9D\x10\xE2\xC7\x38\x07\x72\x0A\x65\xC0\xB6\xBB\x25\x29\xDA\x16\x9E\x8B\x35\x8B\x61\xED\xE5\x71\x57\x83\xB5\x3C\x71\x9F\xE3\x4F\xBF\x7E\x1E\x81\x9F\x41\x97\x02\x03\x01\x00\x01\xA3\x81\x86\x30\x81\x83\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x86\x30\x1D\x06\x03\x55\x1D\x21\x04\x16\x30\x14\x30\x12\x06\x07\x60\x85\x74\x01\x53\x02\x02\x06\x07\x60\x85\x74\x01\x53\x02\x02\x30\x12\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x08\x30\x06\x01\x01\xFF\x02\x01\x03\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x45\xD9\xA5\x81\x6E\x3D\x88\x4D\x8D\x71\xD2\x46\xC1\x6E\x45\x1E\xF3\xC4\x80\x9D\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\x45\xD9\xA5\x81\x6E\x3D\x88\x4D\x8D\x71\xD2\x46\xC1\x6E\x45\x1E\xF3\xC4\x80\x9D\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x03\x82\x02\x01\x00\x94\x3A\x73\x06\x9F\x52\x4B\x30\x5C\xD4\xFE\xB1\x5C\x25\xF9\xD7\x8E\x6F\xF5\x87\x64\x9F\xED\x14\x8E\xB8\x04\x8E\x28\x4B\x8F\xAA\x7B\x8E\x39\xB4\xD9\x58\xF6\x7B\xA1\x35\x0A\xA1\x9D\x8A\xF7\x63\xE5\xEB\xBD\x39\x82\xD4\xE3\x7A\x2D\x6F\xDF\x13\x3C\xBA\xFE\x7E\x56\x98\x0B\xF3\x54\x9F\xCD\x44\x4E\x6E\x3C\xE1\x3E\x15\xBF\x06\x26\x9D\xE4\xF0\x90\xB6\xD4\xC2\x9E\x30\x2E\x1F\xEF\xC7\x7A\xC4\x50\xC7\xEA\x7B\xDA\x50\xCB\x7A\x26\xCB\x00\xB4\x5A\xAB\xB5\x93\x1F\x80\x89\x84\x04\x95\x8D\x8D\x7F\x09\x93\xBF\xD4\xA8\xA8\xE4\x63\x6D\xD9\x64\xE4\xB8\x29\x5A\x08\xBF\x50\xE1\x84\x0F\x55\x7B\x5F\x08\x22\x1B\xF5\xBD\x99\x1E\x14\xF6\xCE\xF4\x58\x10\x82\xB3\x0A\x3D\x19\xC1\xBF\x5B\xAB\xAA\x99\xD8\xF2\x31\xBD\xE5\x38\x66\xDC\x58\x05\xC7\xED\x63\x1A\x2E\x0A\x97\x7C\x87\x93\x2B\xB2\x8A\xE3\xF1\xEC\x18\xE5\x75\xB6\x29\x87\xE7\xDC\x8B\x1A\x7E\xB4\xD8\xC9\xD3\x8A\x17\x6C\x7D\x29\x44\xBE\x8A\xAA\xF5\x7E\x3A\x2E\x68\x31\x93\xB9\x6A\xDA\x9A\xE0\xDB\xE9\x2E\xA5\x84\xCD\x1C\x0A\xB8\x4A\x08\xF9\x9C\xF1\x61\x26\x98\x93\xB7\x7B\x66\xEC\x91\x5E\xDD\x51\x3F\xDB\x73\x0F\xAD\x04\x58\x09\xDD\x04\x02\x95\x0A\x3E\xD3\x76\xDF\xA6\x10\x1E\x80\x3D\xE8\xCD\xA4\x64\xD1\x33\xC7\x92\xC7\xE2\x4E\x44\xE3\x09\xC9\x4E\xC2\x5D\x87\x0E\x12\x9E\xBF\x0F\xC9\x05\x10\xDE\x7A\xA3\xB1\x3C\xF2\x3F\xA5\xAA\x27\x79\xAD\x31\x7D\x1F\xFD\xFC\x19\x69\xC5\xDD\xB9\x3F\x7C\xCD\xC6\xB4\xC2\x30\x1E\x7E\x6E\x92\xD7\x7F\x61\x76\x5A\x8F\xEB\x95\x4D\xBC\x11\x6E\x21\x7C\x59\x37\x99\xD0\x06\xBC\xF9\x06\x6D\x32\x16\xA5\xD9\x69\xA8\xE1\xDC\x3C\x80\x1E\x60\x51\xDC\xD7\x54\x21\x1E\xCA\x62\x77\x4F\xFA\xD8\x8F\xB3\x2B\x3A\x0D\x78\x72\xC9\x68\x41\x5A\x47\x4A\xC2\xA3\xEB\x1A\xD7\x0A\xAB\x3C\x32\x55\xC8\x0A\x11\x9C\xDF\x74\xD6\xF0\x40\x15\x1D\xC8\xB9\x8F\xB5\x36\xC5\xAF\xF8\x22\xB8\xCA\x1D\xF3\xD6\xB6\x19\x0F\x9F\x61\x65\x6A\xEA\x74\xC8\x7C\x8F\xC3\x4F\x5D\x65\x82\x1F\xD9\x0D\x89\xDA\x75\x72\xFB\xEF\xF1\x47\x67\x13\xB3\xC8\xD1\x19\x88\x27\x26\x9A\x99\x79\x7F\x1E\xE4\x2C\x3F\x7B\xEE\xF1\xDE\x4D\x8B\x96\x97\xC3\xD5\x3F\x7C\x1B\x23\xED\xA4\xB3\x1D\x16\x72\x43\x4B\x20\xE1\x59\x7E\xC2\xE8\xAD\x26\xBF\xA2\xF7", ["CN=CA Disig Root R1,O=Disig a.s.,L=Bratislava,C=SK"] = "\x30\x82\x05\x69\x30\x82\x03\x51\xA0\x03\x02\x01\x02\x02\x09\x00\xC3\x03\x9A\xEE\x50\x90\x6E\x28\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x52\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x53\x4B\x31\x13\x30\x11\x06\x03\x55\x04\x07\x13\x0A\x42\x72\x61\x74\x69\x73\x6C\x61\x76\x61\x31\x13\x30\x11\x06\x03\x55\x04\x0A\x13\x0A\x44\x69\x73\x69\x67\x20\x61\x2E\x73\x2E\x31\x19\x30\x17\x06\x03\x55\x04\x03\x13\x10\x43\x41\x20\x44\x69\x73\x69\x67\x20\x52\x6F\x6F\x74\x20\x52\x31\x30\x1E\x17\x0D\x31\x32\x30\x37\x31\x39\x30\x39\x30\x36\x35\x36\x5A\x17\x0D\x34\x32\x30\x37\x31\x39\x30\x39\x30\x36\x35\x36\x5A\x30\x52\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x53\x4B\x31\x13\x30\x11\x06\x03\x55\x04\x07\x13\x0A\x42\x72\x61\x74\x69\x73\x6C\x61\x76\x61\x31\x13\x30\x11\x06\x03\x55\x04\x0A\x13\x0A\x44\x69\x73\x69\x67\x20\x61\x2E\x73\x2E\x31\x19\x30\x17\x06\x03\x55\x04\x03\x13\x10\x43\x41\x20\x44\x69\x73\x69\x67\x20\x52\x6F\x6F\x74\x20\x52\x31\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\xAA\xC3\x78\xF7\xDC\x98\xA3\xA7\x5A\x5E\x77\x18\xB2\xDD\x04\x64\x0F\x63\xFD\x9B\x96\x09\x80\xD5\xE8\xAA\xA5\xE2\x9C\x26\x94\x3A\xE8\x99\x73\x8C\x9D\xDF\xD7\xDF\x83\xF3\x78\x4F\x40\xE1\x7F\xD2\xA7\xD2\xE5\xCA\x13\x93\xE7\xED\xC6\x77\x5F\x36\xB5\x94\xAF\xE8\x38\x8E\xDB\x9B\xE5\x7C\xBB\xCC\x8D\xEB\x75\x73\xE1\x24\xCD\xE6\xA7\x2D\x19\x2E\xD8\xD6\x8A\x6B\x14\xEB\x08\x62\x0A\xD8\xDC\xB3\x00\x4D\xC3\x23\x7C\x5F\x43\x08\x23\x32\x12\xDC\xED\x0C\xAD\xC0\x7D\x0F\xA5\x7A\x42\xD9\x5A\x70\xD9\xBF\xA7\xD7\x01\x1C\xF6\x9B\xAB\x8E\xB7\x4A\x86\x78\xA0\x1E\x56\x31\xAE\xEF\x82\x0A\x80\x41\xF7\x1B\xC9\xAE\xAB\x32\x26\xD4\x2C\x6B\xED\x7D\x6B\xE4\xE2\x5E\x22\x0A\x45\xCB\x84\x31\x4D\xAC\xFE\xDB\xD1\x47\xBA\xF9\x60\x97\x39\xB1\x65\xC7\xDE\xFB\x99\xE4\x0A\x22\xB1\x2D\x4D\xE5\x48\x26\x69\xAB\xE2\xAA\xF3\xFB\xFC\x92\x29\x32\xE9\xB3\x3E\x4D\x1F\x27\xA1\xCD\x8E\xB9\x17\xFB\x25\x3E\xC9\x6E\xF3\x77\xDA\x0D\x12\xF6\x5D\xC7\xBB\x36\x10\xD5\x54\xD6\xF3\xE0\xE2\x47\x48\xE6\xDE\x14\xDA\x61\x52\xAF\x26\xB4\xF5\x71\x4F\xC9\xD7\xD2\x06\xDF\x63\xCA\xFF\x21\xE8\x59\x06\xE0\x08\xD5\x84\x15\x53\xF7\x43\xE5\x7C\xC5\xA0\x89\x98\x6B\x73\xC6\x68\xCE\x65\xDE\xBD\x7F\x05\xF7\xB1\xEE\xF6\x57\xA1\x60\x95\xC5\xCC\xEA\x93\x3A\xBE\x99\xAE\x9B\x02\xA3\xAD\xC9\x16\xB5\xCE\xDD\x5E\x99\x78\x7E\x1A\x39\x7E\xB2\xC0\x05\xA4\xC0\x82\xA5\xA3\x47\x9E\x8C\xEA\x5C\xB6\xBC\x67\xDB\xE6\x2A\x4D\xD2\x04\xDC\xA3\xAE\x45\xF7\xBC\x8B\x9C\x1C\xA7\xD6\xD5\x03\xDC\x08\xCB\x2E\x16\xCA\x5C\x40\x33\xE8\x67\xC3\x2E\xE7\xA6\x44\xEA\x11\x45\x1C\x35\x65\x2D\x1E\x45\x61\x24\x1B\x82\x2E\xA5\x9D\x33\x5D\x65\xF8\x41\xF9\x2E\xCB\x94\x3F\x1F\xA3\x0C\x31\x24\x44\xED\xC7\x5E\xAD\x50\xBA\xC6\x41\x9B\xAC\xF0\x17\x65\xC0\xF8\x5D\x6F\x5B\xA0\x0A\x34\x3C\xEE\xD7\xEA\x88\x9F\x98\xF9\xAF\x4E\x24\xFA\x97\xB2\x64\x76\xDA\xAB\xF4\xED\xE3\xC3\x60\xEF\xD5\xF9\x02\xC8\x2D\x9F\x83\xAF\x67\x69\x06\xA7\x31\x55\xD5\xCF\x4B\x6F\xFF\x04\x05\xC7\x58\xAC\x5F\x16\x1B\xE5\xD2\xA3\xEB\x31\xDB\x1F\x33\x15\x4D\xD0\xF2\xA5\x53\xF5\xCB\xE1\x3D\x4E\x68\x2D\xD8\x12\xDD\xAA\xF2\xE6\x4D\x9B\x49\xE5\xC5\x28\xA1\xBA\xB0\x5A\xC6\xA0\xB5\x02\x03\x01\x00\x01\xA3\x42\x30\x40\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x89\x0A\xB4\x38\x93\x1A\xE6\xAB\xEE\x9B\x91\x18\xF9\xF5\x3C\x3E\x35\xD0\xD3\x82\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x02\x01\x00\x32\x8B\xF6\x9D\x4A\xC9\xBE\x14\xE5\x8C\xAC\x38\xCA\x3A\x09\xD4\x1B\xCE\x86\xB3\xDD\xEB\xD4\xBA\x28\xBE\x12\xAE\x45\x2C\x04\x74\xAC\x13\x51\xC5\x58\x18\x66\x4D\x82\xDA\xD5\xDC\x93\xC0\x27\xE1\xBE\x7C\x9F\x52\x9E\x12\x56\xF6\xD5\x9C\xA9\xF4\x75\x9C\xFA\x37\x12\x8F\x1C\x93\xEC\x57\xFE\x07\x0F\xAB\xD5\x12\xF7\x0F\xAE\x61\x5E\x56\x80\x49\xF5\xFC\x30\xF5\x9B\x4F\x1F\x41\x2F\x1C\x84\xD3\x89\xC7\xE2\xDA\x02\x76\xED\x09\xCF\x6C\xC1\xB8\x1C\x83\x1C\x16\xFA\x94\xCD\x7D\xA0\xC8\x18\xD2\xC8\x9D\x6E\xF5\xBD\x69\xD4\x6D\x3D\x35\xE8\x1E\xA2\x4F\x60\xD7\x07\x29\xFC\xB2\xA3\xA4\x9D\x6E\x15\x92\x56\x19\x4C\x0A\xB0\xE9\x7C\xD2\x19\x4D\x42\x46\xEC\xBD\xFD\xF6\x57\x5B\xDD\x98\x7E\xA4\x4D\xCC\x72\x03\x83\x58\x5D\xEF\x93\x3A\x41\x7A\x63\xAA\x7C\x3A\xA8\xF5\xAC\xA4\xD1\xDD\xA2\x2D\xB6\x2A\xFC\x9F\x01\x8E\xE2\x10\xB1\xC4\xCA\xE4\x67\xDB\x55\x25\x19\x3F\xFD\xE8\x36\x7E\xB3\xE1\xE1\x81\xAF\x11\x16\x8B\x50\x97\x60\x19\x82\x00\xC0\x6B\x4D\x73\xB8\xD1\x13\x07\x3E\xEA\xB6\x31\x4F\xF0\x42\x9A\x6D\xE2\x11\x74\xE5\x94\xAC\x8D\x84\x95\x3C\x21\xAF\xC5\xDA\x47\xC8\xDF\x39\x62\x62\xCB\x5B\x50\x0B\xD7\x81\x40\x05\x9C\x9B\xED\xBA\xB6\x8B\x1E\x04\x6F\x96\x20\x39\xED\xA4\x7D\x29\xDB\x48\xCE\x82\xDC\xD4\x02\x8D\x1D\x04\x31\x5A\xC7\x4B\xF0\x6C\x61\x52\xD7\xB4\x51\xC2\x81\x6C\xCD\xE1\xFB\xA7\xA1\xD2\x92\x76\xCF\xB1\x0F\x37\x58\xA4\xF2\x52\x71\x67\x3F\x0C\x88\x78\x80\x89\xC1\xC8\xB5\x1F\x92\x63\xBE\xA7\x7A\x8A\x56\x2C\x1A\xA8\xA6\x9C\xB5\x5D\xB3\x63\xD0\x13\x20\xA1\xEB\x91\x6C\xD0\x8D\x7D\xAF\xDF\x0B\xE4\x17\xB9\x86\x9E\x38\xB1\x94\x0C\x58\x8C\xE0\x55\xAA\x3B\x63\x6D\x9A\x89\x60\xB8\x64\x2A\x92\xC6\x37\xF4\x7E\x43\x43\xB7\x73\xE8\x01\xE7\x7F\x97\x0F\xD7\xF2\x7B\x19\xFD\x1A\xD7\x8F\xC9\xFA\x85\x6B\x7A\x9D\x9E\x89\xB6\xA6\x28\x99\x93\x88\x40\xF7\x3E\xCD\x51\xA3\xCA\xEA\xEF\x79\x47\x21\xB5\xFE\x32\xE2\xC7\xC3\x51\x6F\xBE\x80\x74\xF0\xA4\xC3\x3A\xF2\x4F\xE9\x5F\xDF\x19\x0A\xF2\x3B\x13\x43\xAC\x31\xA4\xB3\xE7\xEB\xFC\x18\xD6\x01\xA9\xF3\x2A\x8F\x36\x0E\xEB\xB4\xB1\xBC\xB7\x4C\xC9\x6B\xBF\xA1\xF3\xD9\xF4\xED\xE2\xF0\xE3\xED\x64\x9E\x3D\x2F\x96\x52\x4F\x80\x53\x8B", ["CN=CA Disig Root R2,O=Disig a.s.,L=Bratislava,C=SK"] = "\x30\x82\x05\x69\x30\x82\x03\x51\xA0\x03\x02\x01\x02\x02\x09\x00\x92\xB8\x88\xDB\xB0\x8A\xC1\x63\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x30\x52\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x53\x4B\x31\x13\x30\x11\x06\x03\x55\x04\x07\x13\x0A\x42\x72\x61\x74\x69\x73\x6C\x61\x76\x61\x31\x13\x30\x11\x06\x03\x55\x04\x0A\x13\x0A\x44\x69\x73\x69\x67\x20\x61\x2E\x73\x2E\x31\x19\x30\x17\x06\x03\x55\x04\x03\x13\x10\x43\x41\x20\x44\x69\x73\x69\x67\x20\x52\x6F\x6F\x74\x20\x52\x32\x30\x1E\x17\x0D\x31\x32\x30\x37\x31\x39\x30\x39\x31\x35\x33\x30\x5A\x17\x0D\x34\x32\x30\x37\x31\x39\x30\x39\x31\x35\x33\x30\x5A\x30\x52\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x53\x4B\x31\x13\x30\x11\x06\x03\x55\x04\x07\x13\x0A\x42\x72\x61\x74\x69\x73\x6C\x61\x76\x61\x31\x13\x30\x11\x06\x03\x55\x04\x0A\x13\x0A\x44\x69\x73\x69\x67\x20\x61\x2E\x73\x2E\x31\x19\x30\x17\x06\x03\x55\x04\x03\x13\x10\x43\x41\x20\x44\x69\x73\x69\x67\x20\x52\x6F\x6F\x74\x20\x52\x32\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\xA2\xA3\xC4\x00\x09\xD6\x85\x5D\x2D\x6D\x14\xF6\xC2\xC3\x73\x9E\x35\xC2\x71\x55\x7E\x81\xFB\xAB\x46\x50\xE0\xC1\x7C\x49\x78\xE6\xAB\x79\x58\x3C\xDA\xFF\x7C\x1C\x9F\xD8\x97\x02\x78\x3E\x6B\x41\x04\xE9\x41\xBD\xBE\x03\x2C\x45\xF6\x2F\x64\xD4\xAB\x5D\xA3\x47\x3D\x64\x9B\xE9\x68\x9A\xC6\xCC\x1B\x3F\xBA\xBE\xB2\x8B\x34\x02\x2E\x98\x55\x19\xFC\x8C\x6F\xAA\x5F\xDA\x4C\xCE\x4D\x03\x21\xA3\xD8\xD2\x34\x93\x56\x96\xCB\x4C\x0C\x00\x16\x3C\x5F\x1A\xCD\xC8\xC7\x6C\xA6\xAD\xD3\x31\xA7\xBC\xE8\xE5\xE1\x66\xD6\xD2\xFB\x03\xB4\x41\x65\xC9\x10\xAE\x0E\x05\x63\xC6\x80\x6A\x69\x30\xFD\xD2\xEE\x90\xEF\x0D\x27\xDF\x9F\x95\x73\xF4\xE1\x25\xDA\x6C\x16\xDE\x41\x38\x34\xEA\x8B\xFC\xD1\xE8\x04\x14\x61\x2D\x41\x7E\xAC\xC7\x77\x4E\xCB\x51\x54\xFB\x5E\x92\x18\x1B\x04\x5A\x68\xC6\xC9\xC4\xFA\xB7\x13\xA0\x98\xB7\x11\x2B\xB7\xD6\x57\xCC\x7C\x9E\x17\xD1\xCB\x25\xFE\x86\x4E\x24\x2E\x56\x0C\x78\x4D\x9E\x01\x12\xA6\x2B\xA7\x01\x65\x6E\x7C\x62\x1D\x84\x84\xDF\xEA\xC0\x6B\xB5\xA5\x2A\x95\x83\xC3\x53\x11\x0C\x73\x1D\x0B\xB2\x46\x90\xD1\x42\x3A\xCE\x40\x6E\x95\xAD\xFF\xC6\x94\xAD\x6E\x97\x84\x8E\x7D\x6F\x9E\x8A\x80\x0D\x49\x6D\x73\xE2\x7B\x92\x1E\xC3\xF3\xC1\xF3\xEB\x2E\x05\x6F\xD9\x1B\xCF\x37\x76\x04\xC8\xB4\x5A\xE4\x17\xA7\xCB\xDD\x76\x1F\xD0\x19\x76\xE8\x2C\x05\xB3\xD6\x9C\x34\xD8\x96\xDC\x61\x87\x91\x05\xE4\x44\x08\x33\xC1\xDA\xB9\x08\x65\xD4\xAE\xB2\x36\x0D\xEB\xBA\x38\xBA\x0C\xE5\x9B\x9E\xEB\x8D\x66\xDD\x99\xCF\xD6\x89\x41\xF6\x04\x92\x8A\x29\x29\x6D\x6B\x3A\x1C\xE7\x75\x7D\x02\x71\x0E\xF3\xC0\xE7\xBD\xCB\x19\xDD\x9D\x60\xB2\xC2\x66\x60\xB6\xB1\x04\xEE\xC9\xE6\x86\xB9\x9A\x66\x40\xA8\xE7\x11\xED\x81\x45\x03\x8B\xF6\x67\x59\xE8\xC1\x06\x11\xBD\xDD\xCF\x80\x02\x4F\x65\x40\x78\x5C\x47\x50\xC8\x9B\xE6\x1F\x81\x7B\xE4\x44\xA8\x5B\x85\x9A\xE2\xDE\x5A\xD5\xC7\xF9\x3A\x44\x66\x4B\xE4\x32\x54\x7C\xE4\x6C\x9C\xB3\x0E\x3D\x17\xA2\xB2\x34\x12\xD6\x7E\xB2\xA8\x49\xBB\xD1\x7A\x28\x40\xBE\xA2\x16\x1F\xDF\xE4\x37\x1F\x11\x73\xFB\x90\x0A\x65\x43\xA2\x0D\x7C\xF8\x06\x01\x55\x33\x7D\xB0\x0D\xB8\xF4\xF5\xAE\xA5\x42\x57\x7C\x36\x11\x8C\x7B\x5E\xC4\x03\x9D\x8C\x79\x9D\x02\x03\x01\x00\x01\xA3\x42\x30\x40\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xB5\x99\xF8\xAF\xB0\x94\xF5\xE3\x20\xD6\x0A\xAD\xCE\x4E\x56\xA4\x2E\x6E\x42\xED\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x03\x82\x02\x01\x00\x26\x06\x5E\x70\xE7\x65\x33\xC8\x82\x6E\xD9\x9C\x17\x3A\x1B\x7A\x66\xB2\x01\xF6\x78\x3B\x69\x5E\x2F\xEA\xFF\x4E\xF9\x28\xC3\x98\x2A\x61\x4C\xB4\x24\x12\x8A\x7D\x6D\x11\x14\xF7\x9C\xB5\xCA\xE6\xBC\x9E\x27\x8E\x4C\x19\xC8\xA9\xBD\x7A\xC0\xD7\x36\x0E\x6D\x85\x72\x6E\xA8\xC6\xA2\x6D\xF6\xFA\x73\x63\x7F\xBC\x6E\x79\x08\x1C\x9D\x8A\x9F\x1A\x8A\x53\xA6\xD8\xBB\xD9\x35\x55\xB1\x11\xC5\xA9\x03\xB3\x56\x3B\xB9\x84\x93\x22\x5E\x7E\xC1\xF6\x12\x52\x8B\xEA\x2C\x67\xBC\xFE\x36\x4C\xF5\xB8\xCF\xD1\xB3\x49\x92\x3B\xD3\x29\x0E\x99\x1B\x96\xF7\x61\xB8\x3B\xC4\x2B\xB6\x78\x6C\xB4\x23\x6F\xF0\xFD\xD3\xB2\x5E\x75\x1F\x99\x95\xA8\xAC\xF6\xDA\xE1\xC5\x31\x7B\xFB\xD1\x46\xB3\xD2\xBC\x67\xB4\x62\x54\xBA\x09\xF7\x63\xB0\x93\xA2\x9A\xF9\xE9\x52\x2E\x8B\x60\x12\xAB\xFC\xF5\x60\x56\xEF\x10\x5C\x8B\xC4\x1A\x42\xDC\x83\x5B\x64\x0E\xCB\xB5\xBC\xD6\x4F\xC1\x7C\x3C\x6E\x8D\x13\x6D\xFB\x7B\xEB\x30\xD0\xDC\x4D\xAF\xC5\xD5\xB6\xA5\x4C\x5B\x71\xC9\xE8\x31\xBE\xE8\x38\x06\x48\xA1\x1A\xE2\xEA\xD2\xDE\x12\x39\x58\x1A\xFF\x80\x0E\x82\x75\xE6\xB7\xC9\x07\x6C\x0E\xEF\xFF\x38\xF1\x98\x71\xC4\xB7\x7F\x0E\x15\xD0\x25\x69\xBD\x22\x9D\x2B\xED\x05\xF6\x46\x47\xAC\xED\xC0\xF0\xD4\x3B\xE2\xEC\xEE\x96\x5B\x90\x13\x4E\x1E\x56\x3A\xEB\xB0\xEF\x96\xBB\x96\x23\x11\xBA\xF2\x43\x86\x74\x64\x95\xC8\x28\x75\xDF\x1D\x35\xBA\xD2\x37\x83\x38\x53\x38\x36\x3B\xCF\x6C\xE9\xF9\x6B\x0E\xD0\xFB\x04\xE8\x4F\x77\xD7\x65\x01\x78\x86\x0C\x7A\x3E\x21\x62\xF1\x7F\x63\x71\x0C\xC9\x9F\x44\xDB\xA8\x27\xA2\x75\xBE\x6E\x81\x3E\xD7\xC0\xEB\x1B\x98\x0F\x70\x5C\x34\xB2\x8A\xCC\xC0\x85\x18\xEB\x6E\x7A\xB3\xF7\x5A\xA1\x07\xBF\xA9\x42\x92\xF3\x60\x22\x97\xE4\x14\xA1\x07\x9B\x4E\x76\xC0\x8E\x7D\xFD\xA4\x25\xC7\x47\xED\xFF\x1F\x73\xAC\xCC\xC3\xA5\xE9\x6F\x0A\x8E\x9B\x65\xC2\x50\x85\xB5\xA3\xA0\x53\x12\xCC\x55\x87\x61\xF3\x81\xAE\x10\x46\x61\xBD\x44\x21\xB8\xC2\x3D\x74\xCF\x7E\x24\x35\xFA\x1C\x07\x0E\x9B\x3D\x22\xCA\xEF\x31\x2F\x8C\xAC\x12\xBD\xEF\x40\x28\xFC\x29\x67\x9F\xB2\x13\x4F\x66\x24\xC4\x53\x19\xE9\x1E\x29\x15\xEF\xE6\x6D\xB0\x7F\x2D\x67\xFD\xF3\x6C\x1B\x75\x46\xA3\xE5\x4A\x17\xE9\xA4\xD7\x0B", + ["C=ES,O=ACCV,OU=PKIACCV,CN=ACCVRAIZ1"] = "\x30\x82\x07\xD3\x30\x82\x05\xBB\xA0\x03\x02\x01\x02\x02\x08\x5E\xC3\xB7\xA6\x43\x7F\xA4\xE0\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x42\x31\x12\x30\x10\x06\x03\x55\x04\x03\x0C\x09\x41\x43\x43\x56\x52\x41\x49\x5A\x31\x31\x10\x30\x0E\x06\x03\x55\x04\x0B\x0C\x07\x50\x4B\x49\x41\x43\x43\x56\x31\x0D\x30\x0B\x06\x03\x55\x04\x0A\x0C\x04\x41\x43\x43\x56\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x45\x53\x30\x1E\x17\x0D\x31\x31\x30\x35\x30\x35\x30\x39\x33\x37\x33\x37\x5A\x17\x0D\x33\x30\x31\x32\x33\x31\x30\x39\x33\x37\x33\x37\x5A\x30\x42\x31\x12\x30\x10\x06\x03\x55\x04\x03\x0C\x09\x41\x43\x43\x56\x52\x41\x49\x5A\x31\x31\x10\x30\x0E\x06\x03\x55\x04\x0B\x0C\x07\x50\x4B\x49\x41\x43\x43\x56\x31\x0D\x30\x0B\x06\x03\x55\x04\x0A\x0C\x04\x41\x43\x43\x56\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x45\x53\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\x9B\xA9\xAB\xBF\x61\x4A\x97\xAF\x2F\x97\x66\x9A\x74\x5F\xD0\xD9\x96\xFD\xCF\xE2\xE4\x66\xEF\x1F\x1F\x47\x33\xC2\x44\xA3\xDF\x9A\xDE\x1F\xB5\x54\xDD\x15\x7C\x69\x35\x11\x6F\xBB\xC8\x0C\x8E\x6A\x18\x1E\xD8\x8F\xD9\x16\xBC\x10\x48\x36\x5C\xF0\x63\xB3\x90\x5A\x5C\x24\x37\xD7\xA3\xD6\xCB\x09\x71\xB9\xF1\x01\x72\x84\xB0\x7D\xDB\x4D\x80\xCD\xFC\xD3\x6F\xC9\xF8\xDA\xB6\x0E\x82\xD2\x45\x85\xA8\x1B\x68\xA8\x3D\xE8\xF4\x44\x6C\xBD\xA1\xC2\xCB\x03\xBE\x8C\x3E\x13\x00\x84\xDF\x4A\x48\xC0\xE3\x22\x0A\xE8\xE9\x37\xA7\x18\x4C\xB1\x09\x0D\x23\x56\x7F\x04\x4D\xD9\x17\x84\x18\xA5\xC8\xDA\x40\x94\x73\xEB\xCE\x0E\x57\x3C\x03\x81\x3A\x9D\x0A\xA1\x57\x43\x69\xAC\x57\x6D\x79\x90\x78\xE5\xB5\xB4\x3B\xD8\xBC\x4C\x8D\x28\xA1\xA7\xA3\xA7\xBA\x02\x4E\x25\xD1\x2A\xAE\xED\xAE\x03\x22\xB8\x6B\x20\x0F\x30\x28\x54\x95\x7F\xE0\xEE\xCE\x0A\x66\x9D\xD1\x40\x2D\x6E\x22\xAF\x9D\x1A\xC1\x05\x19\xD2\x6F\xC0\xF2\x9F\xF8\x7B\xB3\x02\x42\xFB\x50\xA9\x1D\x2D\x93\x0F\x23\xAB\xC6\xC1\x0F\x92\xFF\xD0\xA2\x15\xF5\x53\x09\x71\x1C\xFF\x45\x13\x84\xE6\x26\x5E\xF8\xE0\x88\x1C\x0A\xFC\x16\xB6\xA8\x73\x06\xB8\xF0\x63\x84\x02\xA0\xC6\x5A\xEC\xE7\x74\xDF\x70\xAE\xA3\x83\x25\xEA\xD6\xC7\x97\x87\x93\xA7\xC6\x8A\x8A\x33\x97\x60\x37\x10\x3E\x97\x3E\x6E\x29\x15\xD6\xA1\x0F\xD1\x88\x2C\x12\x9F\x6F\xAA\xA4\xC6\x42\xEB\x41\xA2\xE3\x95\x43\xD3\x01\x85\x6D\x8E\xBB\x3B\xF3\x23\x36\xC7\xFE\x3B\xE0\xA1\x25\x07\x48\xAB\xC9\x89\x74\xFF\x08\x8F\x80\xBF\xC0\x96\x65\xF3\xEE\xEC\x4B\x68\xBD\x9D\x88\xC3\x31\xB3\x40\xF1\xE8\xCF\xF6\x38\xBB\x9C\xE4\xD1\x7F\xD4\xE5\x58\x9B\x7C\xFA\xD4\xF3\x0E\x9B\x75\x91\xE4\xBA\x52\x2E\x19\x7E\xD1\xF5\xCD\x5A\x19\xFC\xBA\x06\xF6\xFB\x52\xA8\x4B\x99\x04\xDD\xF8\xF9\xB4\x8B\x50\xA3\x4E\x62\x89\xF0\x87\x24\xFA\x83\x42\xC1\x87\xFA\xD5\x2D\x29\x2A\x5A\x71\x7A\x64\x6A\xD7\x27\x60\x63\x0D\xDB\xCE\x49\xF5\x8D\x1F\x90\x89\x32\x17\xF8\x73\x43\xB8\xD2\x5A\x93\x86\x61\xD6\xE1\x75\x0A\xEA\x79\x66\x76\x88\x4F\x71\xEB\x04\x25\xD6\x0A\x5A\x7A\x93\xE5\xB9\x4B\x17\x40\x0F\xB1\xB6\xB9\xF5\xDE\x4F\xDC\xE0\xB3\xAC\x3B\x11\x70\x60\x84\x4A\x43\x6E\x99\x20\xC0\x29\x71\x0A\xC0\x65\x02\x03\x01\x00\x01\xA3\x82\x02\xCB\x30\x82\x02\xC7\x30\x7D\x06\x08\x2B\x06\x01\x05\x05\x07\x01\x01\x04\x71\x30\x6F\x30\x4C\x06\x08\x2B\x06\x01\x05\x05\x07\x30\x02\x86\x40\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x61\x63\x63\x76\x2E\x65\x73\x2F\x66\x69\x6C\x65\x61\x64\x6D\x69\x6E\x2F\x41\x72\x63\x68\x69\x76\x6F\x73\x2F\x63\x65\x72\x74\x69\x66\x69\x63\x61\x64\x6F\x73\x2F\x72\x61\x69\x7A\x61\x63\x63\x76\x31\x2E\x63\x72\x74\x30\x1F\x06\x08\x2B\x06\x01\x05\x05\x07\x30\x01\x86\x13\x68\x74\x74\x70\x3A\x2F\x2F\x6F\x63\x73\x70\x2E\x61\x63\x63\x76\x2E\x65\x73\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xD2\x87\xB4\xE3\xDF\x37\x27\x93\x55\xF6\x56\xEA\x81\xE5\x36\xCC\x8C\x1E\x3F\xBD\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\xD2\x87\xB4\xE3\xDF\x37\x27\x93\x55\xF6\x56\xEA\x81\xE5\x36\xCC\x8C\x1E\x3F\xBD\x30\x82\x01\x73\x06\x03\x55\x1D\x20\x04\x82\x01\x6A\x30\x82\x01\x66\x30\x82\x01\x62\x06\x04\x55\x1D\x20\x00\x30\x82\x01\x58\x30\x82\x01\x22\x06\x08\x2B\x06\x01\x05\x05\x07\x02\x02\x30\x82\x01\x14\x1E\x82\x01\x10\x00\x41\x00\x75\x00\x74\x00\x6F\x00\x72\x00\x69\x00\x64\x00\x61\x00\x64\x00\x20\x00\x64\x00\x65\x00\x20\x00\x43\x00\x65\x00\x72\x00\x74\x00\x69\x00\x66\x00\x69\x00\x63\x00\x61\x00\x63\x00\x69\x00\xF3\x00\x6E\x00\x20\x00\x52\x00\x61\x00\xED\x00\x7A\x00\x20\x00\x64\x00\x65\x00\x20\x00\x6C\x00\x61\x00\x20\x00\x41\x00\x43\x00\x43\x00\x56\x00\x20\x00\x28\x00\x41\x00\x67\x00\x65\x00\x6E\x00\x63\x00\x69\x00\x61\x00\x20\x00\x64\x00\x65\x00\x20\x00\x54\x00\x65\x00\x63\x00\x6E\x00\x6F\x00\x6C\x00\x6F\x00\x67\x00\xED\x00\x61\x00\x20\x00\x79\x00\x20\x00\x43\x00\x65\x00\x72\x00\x74\x00\x69\x00\x66\x00\x69\x00\x63\x00\x61\x00\x63\x00\x69\x00\xF3\x00\x6E\x00\x20\x00\x45\x00\x6C\x00\x65\x00\x63\x00\x74\x00\x72\x00\xF3\x00\x6E\x00\x69\x00\x63\x00\x61\x00\x2C\x00\x20\x00\x43\x00\x49\x00\x46\x00\x20\x00\x51\x00\x34\x00\x36\x00\x30\x00\x31\x00\x31\x00\x35\x00\x36\x00\x45\x00\x29\x00\x2E\x00\x20\x00\x43\x00\x50\x00\x53\x00\x20\x00\x65\x00\x6E\x00\x20\x00\x68\x00\x74\x00\x74\x00\x70\x00\x3A\x00\x2F\x00\x2F\x00\x77\x00\x77\x00\x77\x00\x2E\x00\x61\x00\x63\x00\x63\x00\x76\x00\x2E\x00\x65\x00\x73\x30\x30\x06\x08\x2B\x06\x01\x05\x05\x07\x02\x01\x16\x24\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x61\x63\x63\x76\x2E\x65\x73\x2F\x6C\x65\x67\x69\x73\x6C\x61\x63\x69\x6F\x6E\x5F\x63\x2E\x68\x74\x6D\x30\x55\x06\x03\x55\x1D\x1F\x04\x4E\x30\x4C\x30\x4A\xA0\x48\xA0\x46\x86\x44\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x61\x63\x63\x76\x2E\x65\x73\x2F\x66\x69\x6C\x65\x61\x64\x6D\x69\x6E\x2F\x41\x72\x63\x68\x69\x76\x6F\x73\x2F\x63\x65\x72\x74\x69\x66\x69\x63\x61\x64\x6F\x73\x2F\x72\x61\x69\x7A\x61\x63\x63\x76\x31\x5F\x64\x65\x72\x2E\x63\x72\x6C\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x17\x06\x03\x55\x1D\x11\x04\x10\x30\x0E\x81\x0C\x61\x63\x63\x76\x40\x61\x63\x63\x76\x2E\x65\x73\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x02\x01\x00\x97\x31\x02\x9F\xE7\xFD\x43\x67\x48\x44\x14\xE4\x29\x87\xED\x4C\x28\x66\xD0\x8F\x35\xDA\x4D\x61\xB7\x4A\x97\x4D\xB5\xDB\x90\xE0\x05\x2E\x0E\xC6\x79\xD0\xF2\x97\x69\x0F\xBD\x04\x47\xD9\xBE\xDB\xB5\x29\xDA\x9B\xD9\xAE\xA9\x99\xD5\xD3\x3C\x30\x93\xF5\x8D\xA1\xA8\xFC\x06\x8D\x44\xF4\xCA\x16\x95\x7C\x33\xDC\x62\x8B\xA8\x37\xF8\x27\xD8\x09\x2D\x1B\xEF\xC8\x14\x27\x20\xA9\x64\x44\xFF\x2E\xD6\x75\xAA\x6C\x4D\x60\x40\x19\x49\x43\x54\x63\xDA\xE2\xCC\xBA\x66\xE5\x4F\x44\x7A\x5B\xD9\x6A\x81\x2B\x40\xD5\x7F\xF9\x01\x27\x58\x2C\xC8\xED\x48\x91\x7C\x3F\xA6\x00\xCF\xC4\x29\x73\x11\x36\xDE\x86\x19\x3E\x9D\xEE\x19\x8A\x1B\xD5\xB0\xED\x8E\x3D\x9C\x2A\xC0\x0D\xD8\x3D\x66\xE3\x3C\x0D\xBD\xD5\x94\x5C\xE2\xE2\xA7\x35\x1B\x04\x00\xF6\x3F\x5A\x8D\xEA\x43\xBD\x5F\x89\x1D\xA9\xC1\xB0\xCC\x99\xE2\x4D\x00\x0A\xDA\xC9\x27\x5B\xE7\x13\x90\x5C\xE4\xF5\x33\xA2\x55\x6D\xDC\xE0\x09\x4D\x2F\xB1\x26\x5B\x27\x75\x00\x09\xC4\x62\x77\x29\x08\x5F\x9E\x59\xAC\xB6\x7E\xAD\x9F\x54\x30\x22\x03\xC1\x1E\x71\x64\xFE\xF9\x38\x0A\x96\x18\xDD\x02\x14\xAC\x23\xCB\x06\x1C\x1E\xA4\x7D\x8D\x0D\xDE\x27\x41\xE8\xAD\xDA\x15\xB7\xB0\x23\xDD\x2B\xA8\xD3\xDA\x25\x87\xED\xE8\x55\x44\x4D\x88\xF4\x36\x7E\x84\x9A\x78\xAC\xF7\x0E\x56\x49\x0E\xD6\x33\x25\xD6\x84\x50\x42\x6C\x20\x12\x1D\x2A\xD5\xBE\xBC\xF2\x70\x81\xA4\x70\x60\xBE\x05\xB5\x9B\x9E\x04\x44\xBE\x61\x23\xAC\xE9\xA5\x24\x8C\x11\x80\x94\x5A\xA2\xA2\xB9\x49\xD2\xC1\xDC\xD1\xA7\xED\x31\x11\x2C\x9E\x19\xA6\xEE\xE1\x55\xE1\xC0\xEA\xCF\x0D\x84\xE4\x17\xB7\xA2\x7C\xA5\xDE\x55\x25\x06\xEE\xCC\xC0\x87\x5C\x40\xDA\xCC\x95\x3F\x55\xE0\x35\xC7\xB8\x84\xBE\xB4\x5D\xCD\x7A\x83\x01\x72\xEE\x87\xE6\x5F\x1D\xAE\xB5\x85\xC6\x26\xDF\xE6\xC1\x9A\xE9\x1E\x02\x47\x9F\x2A\xA8\x6D\xA9\x5B\xCF\xEC\x45\x77\x7F\x98\x27\x9A\x32\x5D\x2A\xE3\x84\xEE\xC5\x98\x66\x2F\x96\x20\x1D\xDD\xD8\xC3\x27\xD7\xB0\xF9\xFE\xD9\x7D\xCD\xD0\x9F\x8F\x0B\x14\x58\x51\x9F\x2F\x8B\xC3\x38\x2D\xDE\xE8\x8F\xD6\x8D\x87\xA4\xF5\x56\x43\x16\x99\x2C\xF4\xA4\x56\xB4\x34\xB8\x61\x37\xC9\xC2\x58\x80\x1B\xA0\x97\xA1\xFC\x59\x8D\xE9\x11\xF6\xD1\x0F\x4B\x55\x34\x46\x2A\x8B\x86\x3B", + ["CN=TWCA Global Root CA,OU=Root CA,O=TAIWAN-CA,C=TW"] = "\x30\x82\x05\x41\x30\x82\x03\x29\xA0\x03\x02\x01\x02\x02\x02\x0C\xBE\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x30\x51\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x54\x57\x31\x12\x30\x10\x06\x03\x55\x04\x0A\x13\x09\x54\x41\x49\x57\x41\x4E\x2D\x43\x41\x31\x10\x30\x0E\x06\x03\x55\x04\x0B\x13\x07\x52\x6F\x6F\x74\x20\x43\x41\x31\x1C\x30\x1A\x06\x03\x55\x04\x03\x13\x13\x54\x57\x43\x41\x20\x47\x6C\x6F\x62\x61\x6C\x20\x52\x6F\x6F\x74\x20\x43\x41\x30\x1E\x17\x0D\x31\x32\x30\x36\x32\x37\x30\x36\x32\x38\x33\x33\x5A\x17\x0D\x33\x30\x31\x32\x33\x31\x31\x35\x35\x39\x35\x39\x5A\x30\x51\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x54\x57\x31\x12\x30\x10\x06\x03\x55\x04\x0A\x13\x09\x54\x41\x49\x57\x41\x4E\x2D\x43\x41\x31\x10\x30\x0E\x06\x03\x55\x04\x0B\x13\x07\x52\x6F\x6F\x74\x20\x43\x41\x31\x1C\x30\x1A\x06\x03\x55\x04\x03\x13\x13\x54\x57\x43\x41\x20\x47\x6C\x6F\x62\x61\x6C\x20\x52\x6F\x6F\x74\x20\x43\x41\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\xB0\x05\xDB\xC8\xEB\x8C\xC4\x6E\x8A\x21\xEF\x8E\x4D\x9C\x71\x0A\x1F\x52\x70\xED\x6D\x82\x9C\x97\xC5\xD7\x4C\x4E\x45\x49\xCB\x40\x42\xB5\x12\x34\x6C\x19\xC2\x74\xA4\x31\x5F\x85\x02\x97\xEC\x43\x33\x0A\x53\xD2\x9C\x8C\x8E\xB7\xB8\x79\xDB\x2B\xD5\x6A\xF2\x8E\x66\xC4\xEE\x2B\x01\x07\x92\xD4\xB3\xD0\x02\xDF\x50\xF6\x55\xAF\x66\x0E\xCB\xE0\x47\x60\x2F\x2B\x32\x39\x35\x52\x3A\x28\x83\xF8\x7B\x16\xC6\x18\xB8\x62\xD6\x47\x25\x91\xCE\xF0\x19\x12\x4D\xAD\x63\xF5\xD3\x3F\x75\x5F\x29\xF0\xA1\x30\x1C\x2A\xA0\x98\xA6\x15\xBD\xEE\xFD\x19\x36\xF0\xE2\x91\x43\x8F\xFA\xCA\xD6\x10\x27\x49\x4C\xEF\xDD\xC1\xF1\x85\x70\x9B\xCA\xEA\xA8\x5A\x43\xFC\x6D\x86\x6F\x73\xE9\x37\x45\xA9\xF0\x36\xC7\xCC\x88\x75\x1E\xBB\x6C\x06\xFF\x9B\x6B\x3E\x17\xEC\x61\xAA\x71\x7C\xC6\x1D\xA2\xF7\x49\xE9\x15\xB5\x3C\xD6\xA1\x61\xF5\x11\xF7\x05\x6F\x1D\xFD\x11\xBE\xD0\x30\x07\xC2\x29\xB0\x09\x4E\x26\xDC\xE3\xA2\xA8\x91\x6A\x1F\xC2\x91\x45\x88\x5C\xE5\x98\xB8\x71\xA5\x15\x19\xC9\x7C\x75\x11\xCC\x70\x74\x4F\x2D\x9B\x1D\x91\x44\xFD\x56\x28\xA0\xFE\xBB\x86\x6A\xC8\xFA\x5C\x0B\x58\xDC\xC6\x4B\x76\xC8\xAB\x22\xD9\x73\x0F\xA5\xF4\x5A\x02\x89\x3F\x4F\x9E\x22\x82\xEE\xA2\x74\x53\x2A\x3D\x53\x27\x69\x1D\x6C\x8E\x32\x2C\x64\x00\x26\x63\x61\x36\x4E\xA3\x46\xB7\x3F\x7D\xB3\x2D\xAC\x6D\x90\xA2\x95\xA2\xCE\xCF\xDA\x82\xE7\x07\x34\x19\x96\xE9\xB8\x21\xAA\x29\x7E\xA6\x38\xBE\x8E\x29\x4A\x21\x66\x79\x1F\xB3\xC3\xB5\x09\x67\xDE\xD6\xD4\x07\x46\xF3\x2A\xDA\xE6\x22\x37\x60\xCB\x81\xB6\x0F\xA0\x0F\xE9\xC8\x95\x7F\xBF\x55\x91\x05\x7A\xCF\x3D\x15\xC0\x6F\xDE\x09\x94\x01\x83\xD7\x34\x1B\xCC\x40\xA5\xF0\xB8\x9B\x67\xD5\x98\x91\x3B\xA7\x84\x78\x95\x26\xA4\x5A\x08\xF8\x2B\x74\xB4\x00\x04\x3C\xDF\xB8\x14\x8E\xE8\xDF\xA9\x8D\x6C\x67\x92\x33\x1D\xC0\xB7\xD2\xEC\x92\xC8\xBE\x09\xBF\x2C\x29\x05\x6F\x02\x6B\x9E\xEF\xBC\xBF\x2A\xBC\x5B\xC0\x50\x8F\x41\x70\x71\x87\xB2\x4D\xB7\x04\xA9\x84\xA3\x32\xAF\xAE\xEE\x6B\x17\x8B\xB2\xB1\xFE\x6C\xE1\x90\x8C\x88\xA8\x97\x48\xCE\xC8\x4D\xCB\xF3\x06\xCF\x5F\x6A\x0A\x42\xB1\x1E\x1E\x77\x2F\x8E\xA0\xE6\x92\x0E\x06\xFC\x05\x22\xD2\x26\xE1\x31\x51\x7D\x32\xDC\x0F\x02\x03\x01\x00\x01\xA3\x23\x30\x21\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x03\x82\x02\x01\x00\x5F\x34\x81\x76\xEF\x96\x1D\xD5\xE5\xB5\xD9\x02\x63\x84\x16\xC1\xAE\xA0\x70\x51\xA7\xF7\x4C\x47\x35\xC8\x0B\xD7\x28\x3D\x89\x71\xD9\xAA\x33\x41\xEA\x14\x1B\x6C\x21\x00\xC0\x6C\x42\x19\x7E\x9F\x69\x5B\x20\x42\xDF\xA2\xD2\xDA\xC4\x7C\x97\x4B\x8D\xB0\xE8\xAC\xC8\xEE\xA5\x69\x04\x99\x0A\x92\xA6\xAB\x27\x2E\x1A\x4D\x81\xBF\x84\xD4\x70\x1E\xAD\x47\xFE\xFD\x4A\x9D\x33\xE0\xF2\xB9\xC4\x45\x08\x21\x0A\xDA\x69\x69\x73\x72\x0D\xBE\x34\xFE\x94\x8B\xAD\xC3\x1E\x35\xD7\xA2\x83\xEF\xE5\x38\xC7\xA5\x85\x1F\xAB\xCF\x34\xEC\x3F\x28\xFE\x0C\xF1\x57\x86\x4E\xC9\x55\xF7\x1C\xD4\xD8\xA5\x7D\x06\x7A\x6F\xD5\xDF\x10\xDF\x81\x4E\x21\x65\xB1\xB6\xE1\x17\x79\x95\x45\x06\xCE\x5F\xCC\xDC\x46\x89\x63\x68\x44\x8D\x93\xF4\x64\x70\xA0\x3D\x9D\x28\x05\xC3\x39\x70\xB8\x62\x7B\x20\xFD\xE4\xDB\xE9\x08\xA1\xB8\x9E\x3D\x09\xC7\x4F\xFB\x2C\xF8\x93\x76\x41\xDE\x52\xE0\xE1\x57\xD2\x9D\x03\xBC\x77\x9E\xFE\x9E\x29\x5E\xF7\xC1\x51\x60\x1F\xDE\xDA\x0B\xB2\x2D\x75\xB7\x43\x48\x93\xE7\xF6\x79\xC6\x84\x5D\x80\x59\x60\x94\xFC\x78\x98\x8F\x3C\x93\x51\xED\x40\x90\x07\xDF\x64\x63\x24\xCB\x4E\x71\x05\xA1\xD7\x94\x1A\x88\x32\xF1\x22\x74\x22\xAE\xA5\xA6\xD8\x12\x69\x4C\x60\xA3\x02\xEE\x2B\xEC\xD4\x63\x92\x0B\x5E\xBE\x2F\x76\x6B\xA3\xB6\x26\xBC\x8F\x03\xD8\x0A\xF2\x4C\x64\x46\xBD\x39\x62\xE5\x96\xEB\x34\x63\x11\x28\xCC\x95\xF1\xAD\xEF\xEF\xDC\x80\x58\x48\xE9\x4B\xB8\xEA\x65\xAC\xE9\xFC\x80\xB5\xB5\xC8\x45\xF9\xAC\xC1\x9F\xD9\xB9\xEA\x62\x88\x8E\xC4\xF1\x4B\x83\x12\xAD\xE6\x8B\x84\xD6\x9E\xC2\xEB\x83\x18\x9F\x6A\xBB\x1B\x24\x60\x33\x70\xCC\xEC\xF7\x32\xF3\x5C\xD9\x79\x7D\xEF\x9E\xA4\xFE\xC9\x23\xC3\x24\xEE\x15\x92\xB1\x3D\x91\x4F\x26\x86\xBD\x66\x73\x24\x13\xEA\xA4\xAE\x63\xC1\xAD\x7D\x84\x03\x3C\x10\x78\x86\x1B\x79\xE3\xC4\xF3\xF2\x04\x95\x20\xAE\x23\x82\xC4\xB3\x3A\x00\x62\xBF\xE6\x36\x24\xE1\x57\xBA\xC7\x1E\x90\x75\xD5\x5F\x3F\x95\x61\x2B\xC1\x3B\xCD\xE5\xB3\x68\x61\xD0\x46\x26\xA9\x21\x52\x69\x2D\xEB\x2E\xC7\xEB\x77\xCE\xA6\x3A\xB5\x03\x33\x4F\x76\xD1\xE7\x5C\x54\x01\x5D\xCB\x78\xF4\xC9\x0C\xBF\xCF\x12\x8E\x17\x2D\x23\x68\x94\xE7\xAB\xFE\xA9\xB2\x2B\x06\xD0\x04\xCD", + ["CN=TeliaSonera Root CA v1,O=TeliaSonera"] = "\x30\x82\x05\x38\x30\x82\x03\x20\xA0\x03\x02\x01\x02\x02\x11\x00\x95\xBE\x16\xA0\xF7\x2E\x46\xF1\x7B\x39\x82\x72\xFA\x8B\xCD\x96\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x30\x37\x31\x14\x30\x12\x06\x03\x55\x04\x0A\x0C\x0B\x54\x65\x6C\x69\x61\x53\x6F\x6E\x65\x72\x61\x31\x1F\x30\x1D\x06\x03\x55\x04\x03\x0C\x16\x54\x65\x6C\x69\x61\x53\x6F\x6E\x65\x72\x61\x20\x52\x6F\x6F\x74\x20\x43\x41\x20\x76\x31\x30\x1E\x17\x0D\x30\x37\x31\x30\x31\x38\x31\x32\x30\x30\x35\x30\x5A\x17\x0D\x33\x32\x31\x30\x31\x38\x31\x32\x30\x30\x35\x30\x5A\x30\x37\x31\x14\x30\x12\x06\x03\x55\x04\x0A\x0C\x0B\x54\x65\x6C\x69\x61\x53\x6F\x6E\x65\x72\x61\x31\x1F\x30\x1D\x06\x03\x55\x04\x03\x0C\x16\x54\x65\x6C\x69\x61\x53\x6F\x6E\x65\x72\x61\x20\x52\x6F\x6F\x74\x20\x43\x41\x20\x76\x31\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\xC2\xBE\xEB\x27\xF0\x21\xA3\xF3\x69\x26\x55\x7E\x9D\xC5\x55\x16\x91\x5C\xFD\xEF\x21\xBF\x53\x80\x7A\x2D\xD2\x91\x8C\x63\x31\xF0\xEC\x24\xF0\xC3\xA5\xD2\x72\x7C\x10\x6D\xF4\x37\xB7\xE5\xE6\x7C\x79\xEA\x8C\xB5\x82\x8B\xAE\x48\xB6\xAC\x00\xDC\x65\x75\xEC\x2A\x4D\x5F\xC1\x87\xF5\x20\x65\x2B\x81\xA8\x47\x3E\x89\x23\x95\x30\x16\x90\x7F\xE8\x57\x07\x48\xE7\x19\xAE\xBF\x45\x67\xB1\x37\x1B\x06\x2A\xFE\xDE\xF9\xAC\x7D\x83\xFB\x5E\xBA\xE4\x8F\x97\x67\xBE\x4B\x8E\x8D\x64\x07\x57\x38\x55\x69\x34\x36\x3D\x13\x48\xEF\x4F\xE2\xD3\x66\x1E\xA4\xCF\x1A\xB7\x5E\x36\x33\xD4\xB4\x06\xBD\x18\x01\xFD\x77\x84\x50\x00\x45\xF5\x8C\x5D\xE8\x23\xBC\x7E\xFE\x35\xE1\xED\x50\x7B\xA9\x30\x8D\x19\xD3\x09\x8E\x68\x67\x5D\xBF\x3C\x97\x18\x53\xBB\x29\x62\xC5\xCA\x5E\x72\xC1\xC7\x96\xD4\xDB\x2D\xA0\xB4\x1F\x69\x03\xEC\xEA\xE2\x50\xF1\x0C\x3C\xF0\xAC\xF3\x53\x2D\xF0\x1C\xF5\xED\x6C\x39\x39\x73\x80\x16\xC8\x52\xB0\x23\xCD\xE0\x3E\xDC\xDD\x3C\x47\xA0\xBB\x35\x8A\xE2\x98\x68\x8B\xBE\xE5\xBF\x72\xEE\xD2\xFA\xA5\xED\x12\xED\xFC\x98\x18\xA9\x26\x76\xDC\x28\x4B\x10\x20\x1C\xD3\x7F\x16\x77\x2D\xED\x6F\x80\xF7\x49\xBB\x53\x05\xBB\x5D\x68\xC7\xD4\xC8\x75\x16\x3F\x89\x5A\x8B\xF7\x17\x47\xD4\x4C\xF1\xD2\x89\x79\x3E\x4D\x3D\x98\xA8\x61\xDE\x3A\x1E\xD2\xF8\x5E\x03\xE0\xC1\xC9\x1C\x8C\xD3\x8D\x4D\xD3\x95\x36\xB3\x37\x5F\x63\x63\x9B\x33\x14\xF0\x2D\x26\x6B\x53\x7C\x89\x8C\x32\xC2\x6E\xEC\x3D\x21\x00\x39\xC9\xA1\x68\xE2\x50\x83\x2E\xB0\x3A\x2B\xF3\x36\xA0\xAC\x2F\xE4\x6F\x61\xC2\x51\x09\x39\x3E\x8B\x53\xB9\xBB\x67\xDA\xDC\x53\xB9\x76\x59\x36\x9D\x43\xE5\x20\xE0\x3D\x32\x60\x85\x22\x51\xB7\xC7\x33\xBB\xDD\x15\x2F\xA4\x78\xA6\x07\x7B\x81\x46\x36\x04\x86\xDD\x79\x35\xC7\x95\x2C\x3B\xB0\xA3\x17\x35\xE5\x73\x1F\xB4\x5C\x59\xEF\xDA\xEA\x10\x65\x7B\x7A\xD0\x7F\x9F\xB3\xB4\x2A\x37\x3B\x70\x8B\x9B\x5B\xB9\x2B\xB7\xEC\xB2\x51\x12\x97\x53\x29\x5A\xD4\xF0\x12\x10\xDC\x4F\x02\xBB\x12\x92\x2F\x62\xD4\x3F\x69\x43\x7C\x0D\xD6\xFC\x58\x75\x01\x88\x9D\x58\x16\x4B\xDE\xBA\x90\xFF\x47\x01\x89\x06\x6A\xF6\x5F\xB2\x90\x6A\xB3\x02\xA6\x02\x88\xBF\xB3\x47\x7E\x2A\xD9\xD5\xFA\x68\x78\x35\x4D\x02\x03\x01\x00\x01\xA3\x3F\x30\x3D\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x0B\x06\x03\x55\x1D\x0F\x04\x04\x03\x02\x01\x06\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xF0\x8F\x59\x38\x00\xB3\xF5\x8F\x9A\x96\x0C\xD5\xEB\xFA\x7B\xAA\x17\xE8\x13\x12\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x82\x02\x01\x00\xBE\xE4\x5C\x62\x4E\x24\xF4\x0C\x08\xFF\xF0\xD3\x0C\x68\xE4\x93\x49\x22\x3F\x44\x27\x6F\xBB\x6D\xDE\x83\x66\xCE\xA8\xCC\x0D\xFC\xF5\x9A\x06\xE5\x77\x14\x91\xEB\x9D\x41\x7B\x99\x2A\x84\xE5\xFF\xFC\x21\xC1\x5D\xF0\xE4\x1F\x57\xB7\x75\xA9\xA1\x5F\x02\x26\xFF\xD7\xC7\xF7\x4E\xDE\x4F\xF8\xF7\x1C\x46\xC0\x7A\x4F\x40\x2C\x22\x35\xF0\x19\xB1\xD0\x6B\x67\x2C\xB0\xA8\xE0\xC0\x40\x37\x35\xF6\x84\x5C\x5C\xE3\xAF\x42\x78\xFE\xA7\xC9\x0D\x50\xEA\x0D\x84\x76\xF6\x51\xEF\x83\x53\xC6\x7A\xFF\x0E\x56\x49\x2E\x8F\x7A\xD6\x0C\xE6\x27\x54\xE3\x4D\x0A\x60\x72\x62\xCD\x91\x07\xD6\xA5\xBF\xC8\x99\x6B\xED\xC4\x19\xE6\xAB\x4C\x11\x38\xC5\x6F\x31\xE2\x6E\x49\xC8\x3F\x76\x80\x26\x03\x26\x29\xE0\x36\xF6\xF6\x20\x53\xE3\x17\x70\x34\x17\x9D\x63\x68\x1E\x6B\xEC\xC3\x4D\x86\xB8\x13\x30\x2F\x5D\x46\x0D\x47\x43\xD5\x1B\xAA\x59\x0E\xB9\x5C\x8D\x06\x48\xAD\x74\x87\x5F\xC7\xFC\x31\x54\x41\x13\xE2\xC7\x21\x0E\x9E\xE0\x1E\x0D\xE1\xC0\x7B\x43\x85\x90\xC5\x8A\x58\xC6\x65\x0A\x78\x57\xF2\xC6\x23\x0F\x01\xD9\x20\x4B\xDE\x0F\xFB\x92\x85\x75\x2A\x5C\x73\x8D\x6D\x7B\x25\x91\xCA\xEE\x45\xAE\x06\x4B\x00\xCC\xD3\xB1\x59\x50\xDA\x3A\x88\x3B\x29\x43\x46\x5E\x97\x2B\x54\xCE\x53\x6F\x8D\x4A\xE7\x96\xFA\xBF\x71\x0E\x42\x8B\x7C\xFD\x28\xA0\xD0\x48\xCA\xDA\xC4\x81\x4C\xBB\xA2\x73\x93\x26\xC8\xEB\x0C\xD6\x26\x88\xB6\xC0\x24\xCF\xBB\xBD\x5B\xEB\x75\x7D\xE9\x08\x8E\x86\x33\x2C\x79\x77\x09\x69\xA5\x89\xFC\xB3\x70\x90\x87\x76\x8F\xD3\x22\xBB\x42\xCE\xBD\x73\x0B\x20\x26\x2A\xD0\x9B\x3D\x70\x1E\x24\x6C\xCD\x87\x76\xA9\x17\x96\xB7\xCF\x0D\x92\xFB\x8E\x18\xA9\x98\x49\xD1\x9E\xFE\x60\x44\x72\x21\xB9\x19\xED\xC2\xF5\x31\xF1\x39\x48\x88\x90\x24\x75\x54\x16\xAD\xCE\xF4\xF8\x69\x14\x64\x39\xFB\xA3\xB8\xBA\x70\x40\xC7\x27\x1C\xBF\xC4\x56\x53\xFA\x63\x65\xD0\xF3\x1C\x0E\x16\xF5\x6B\x86\x58\x4D\x18\xD4\xE4\x0D\x8E\xA5\x9D\x5B\x91\xDC\x76\x24\x50\x3F\xC6\x2A\xFB\xD9\xB7\x9C\xB5\xD6\xE6\xD0\xD9\xE8\x19\x8B\x15\x71\x48\xAD\xB7\xEA\xD8\x59\x88\xD4\x90\xBF\x16\xB3\xD9\xE9\xAC\x59\x61\x54\xC8\x1C\xBA\xCA\xC1\xCA\xE1\xB9\x20\x4C\x8F\x3A\x93\x89\xA5\xA0\xCC\xBF\xD3\xF6\x75\xA4\x75\x96\x6D\x56", + ["CN=E-Tugra Certification Authority,OU=E-Tugra Sertifikasyon Merkezi,O=E-Tu\C4\9Fra EBG Bili\C5\9Fim Teknolojileri ve Hizmetleri A.\C5\9E.,L=Ankara,C=TR"] = "\x30\x82\x06\x4B\x30\x82\x04\x33\xA0\x03\x02\x01\x02\x02\x08\x6A\x68\x3E\x9C\x51\x9B\xCB\x53\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x30\x81\xB2\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x54\x52\x31\x0F\x30\x0D\x06\x03\x55\x04\x07\x0C\x06\x41\x6E\x6B\x61\x72\x61\x31\x40\x30\x3E\x06\x03\x55\x04\x0A\x0C\x37\x45\x2D\x54\x75\xC4\x9F\x72\x61\x20\x45\x42\x47\x20\x42\x69\x6C\x69\xC5\x9F\x69\x6D\x20\x54\x65\x6B\x6E\x6F\x6C\x6F\x6A\x69\x6C\x65\x72\x69\x20\x76\x65\x20\x48\x69\x7A\x6D\x65\x74\x6C\x65\x72\x69\x20\x41\x2E\xC5\x9E\x2E\x31\x26\x30\x24\x06\x03\x55\x04\x0B\x0C\x1D\x45\x2D\x54\x75\x67\x72\x61\x20\x53\x65\x72\x74\x69\x66\x69\x6B\x61\x73\x79\x6F\x6E\x20\x4D\x65\x72\x6B\x65\x7A\x69\x31\x28\x30\x26\x06\x03\x55\x04\x03\x0C\x1F\x45\x2D\x54\x75\x67\x72\x61\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x1E\x17\x0D\x31\x33\x30\x33\x30\x35\x31\x32\x30\x39\x34\x38\x5A\x17\x0D\x32\x33\x30\x33\x30\x33\x31\x32\x30\x39\x34\x38\x5A\x30\x81\xB2\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x54\x52\x31\x0F\x30\x0D\x06\x03\x55\x04\x07\x0C\x06\x41\x6E\x6B\x61\x72\x61\x31\x40\x30\x3E\x06\x03\x55\x04\x0A\x0C\x37\x45\x2D\x54\x75\xC4\x9F\x72\x61\x20\x45\x42\x47\x20\x42\x69\x6C\x69\xC5\x9F\x69\x6D\x20\x54\x65\x6B\x6E\x6F\x6C\x6F\x6A\x69\x6C\x65\x72\x69\x20\x76\x65\x20\x48\x69\x7A\x6D\x65\x74\x6C\x65\x72\x69\x20\x41\x2E\xC5\x9E\x2E\x31\x26\x30\x24\x06\x03\x55\x04\x0B\x0C\x1D\x45\x2D\x54\x75\x67\x72\x61\x20\x53\x65\x72\x74\x69\x66\x69\x6B\x61\x73\x79\x6F\x6E\x20\x4D\x65\x72\x6B\x65\x7A\x69\x31\x28\x30\x26\x06\x03\x55\x04\x03\x0C\x1F\x45\x2D\x54\x75\x67\x72\x61\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\xE2\xF5\x3F\x93\x05\x51\x1E\x85\x62\x54\x5E\x7A\x0B\xF5\x18\x07\x83\xAE\x7E\xAF\x7C\xF7\xD4\x8A\x6B\xA5\x63\x43\x39\xB9\x4B\xF7\xC3\xC6\x64\x89\x3D\x94\x2E\x54\x80\x52\x39\x39\x07\x4B\x4B\xDD\x85\x07\x76\x87\xCC\xBF\x2F\x95\x4C\xCC\x7D\xA7\x3D\xBC\x47\x0F\x98\x70\xF8\x8C\x85\x1E\x74\x8E\x92\x6D\x1B\x40\xD1\x99\x0D\xBB\x75\x6E\xC8\xA9\x6B\x9A\xC0\x84\x31\xAF\xCA\x43\xCB\xEB\x2B\x34\xE8\x8F\x97\x6B\x01\x9B\xD5\x0E\x4A\x08\xAA\x5B\x92\x74\x85\x43\xD3\x80\xAE\xA1\x88\x5B\xAE\xB3\xEA\x5E\xCB\x16\x9A\x77\x44\xC8\xA1\xF6\x54\x68\xCE\xDE\x8F\x97\x2B\xBA\x5B\x40\x02\x0C\x64\x17\xC0\xB5\x93\xCD\xE1\xF1\x13\x66\xCE\x0C\x79\xEF\xD1\x91\x28\xAB\x5F\xA0\x12\x52\x30\x73\x19\x8E\x8F\xE1\x8C\x07\xA2\xC3\xBB\x4A\xF0\xEA\x1F\x15\xA8\xEE\x25\xCC\xA4\x46\xF8\x1B\x22\xEF\xB3\x0E\x43\xBA\x2C\x24\xB8\xC5\x2C\x5C\xD4\x1C\xF8\x5D\x64\xBD\xC3\x93\x5E\x28\xA7\x3F\x27\xF1\x8E\x1E\xD3\x2A\x50\x05\xA3\x55\xD9\xCB\xE7\x39\x53\xC0\x98\x9E\x8C\x54\x62\x8B\x26\xB0\xF7\x7D\x8D\x7C\xE4\xC6\x9E\x66\x42\x55\x82\x47\xE7\xB2\x58\x8D\x66\xF7\x07\x7C\x2E\x36\xE6\x50\x1C\x3F\xDB\x43\x24\xC5\xBF\x86\x47\x79\xB3\x79\x1C\xF7\x5A\xF4\x13\xEC\x6C\xF8\x3F\xE2\x59\x1F\x95\xEE\x42\x3E\xB9\xAD\xA8\x32\x85\x49\x97\x46\xFE\x4B\x31\x8F\x5A\xCB\xAD\x74\x47\x1F\xE9\x91\xB7\xDF\x28\x04\x22\xA0\xD4\x0F\x5D\xE2\x79\x4F\xEA\x6C\x85\x86\xBD\xA8\xA6\xCE\xE4\xFA\xC3\xE1\xB3\xAE\xDE\x3C\x51\xEE\xCB\x13\x7C\x01\x7F\x84\x0E\x5D\x51\x94\x9E\x13\x0C\xB6\x2E\xA5\x4C\xF9\x39\x70\x36\x6F\x96\xCA\x2E\x0C\x44\x55\xC5\xCA\xFA\x5D\x02\xA3\xDF\xD6\x64\x8C\x5A\xB3\x01\x0A\xA9\xB5\x0A\x47\x17\xFF\xEF\x91\x40\x2A\x8E\xA1\x46\x3A\x31\x98\xE5\x11\xFC\xCC\xBB\x49\x56\x8A\xFC\xB9\xD0\x61\x9A\x6F\x65\x6C\xE6\xC3\xCB\x3E\x75\x49\xFE\x8F\xA7\xE2\x89\xC5\x67\xD7\x9D\x46\x13\x4E\x31\x76\x3B\x24\xB3\x9E\x11\x65\x86\xAB\x7F\xEF\x1D\xD4\xF8\xBC\xE7\xAC\x5A\x5C\xB7\x5A\x47\x5C\x55\xCE\x55\xB4\x22\x71\x5B\x5B\x0B\xF0\xCF\xDC\xA0\x61\x64\xEA\xA9\xD7\x68\x0A\x63\xA7\xE0\x0D\x3F\xA0\xAF\xD3\xAA\xD2\x7E\xEF\x51\xA0\xE6\x51\x2B\x55\x92\x15\x17\x53\xCB\xB7\x66\x0E\x66\x4C\xF8\xF9\x75\x4C\x90\xE7\x12\x70\xC7\x45\x02\x03\x01\x00\x01\xA3\x63\x30\x61\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x2E\xE3\xDB\xB2\x49\xD0\x9C\x54\x79\x5C\xFA\x27\x2A\xFE\xCC\x4E\xD2\xE8\x4E\x54\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\x2E\xE3\xDB\xB2\x49\xD0\x9C\x54\x79\x5C\xFA\x27\x2A\xFE\xCC\x4E\xD2\xE8\x4E\x54\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x03\x82\x02\x01\x00\x05\x37\x3A\xF4\x4D\xB7\x45\xE2\x45\x75\x24\x8F\xB6\x77\x52\xE8\x1C\xD8\x10\x93\x65\xF3\xF2\x59\x06\xA4\x3E\x1E\x29\xEC\x5D\xD1\xD0\xAB\x7C\xE0\x0A\x90\x48\x78\xED\x4E\x98\x03\x99\xFE\x28\x60\x91\x1D\x30\x1D\xB8\x63\x7C\xA8\xE6\x35\xB5\xFA\xD3\x61\x76\xE6\xD6\x07\x4B\xCA\x69\x9A\xB2\x84\x7A\x77\x93\x45\x17\x15\x9F\x24\xD0\x98\x13\x12\xFF\xBB\xA0\x2E\xFD\x4E\x4C\x87\xF8\xCE\x5C\xAA\x98\x1B\x05\xE0\x00\x46\x4A\x82\x80\xA5\x33\x8B\x28\xDC\xED\x38\xD3\xDF\xE5\x3E\xE9\xFE\xFB\x59\xDD\x61\x84\x4F\xD2\x54\x96\x13\x61\x13\x3E\x8F\x80\x69\xBE\x93\x47\xB5\x35\x43\xD2\x5A\xBB\x3D\x5C\xEF\xB3\x42\x47\xCD\x3B\x55\x13\x06\xB0\x09\xDB\xFD\x63\xF6\x3A\x88\x0A\x99\x6F\x7E\xE1\xCE\x1B\x53\x6A\x44\x66\x23\x51\x08\x7B\xBC\x5B\x52\xA2\xFD\x06\x37\x38\x40\x61\x8F\x4A\x96\xB8\x90\x37\xF8\x66\xC7\x78\x90\x00\x15\x2E\x8B\xAD\x51\x35\x53\x07\xA8\x6B\x68\xAE\xF9\x4E\x3C\x07\x26\xCD\x08\x05\x70\xCC\x39\x3F\x76\xBD\xA5\xD3\x67\x26\x01\x86\xA6\x53\xD2\x60\x3B\x7C\x43\x7F\x55\x8A\xBC\x95\x1A\xC1\x28\x39\x4C\x1F\x43\xD2\x91\xF4\x72\x59\x8A\xB9\x56\xFC\x3F\xB4\x9D\xDA\x70\x9C\x76\x5A\x8C\x43\x50\xEE\x8E\x30\x72\x4D\xDF\xFF\x49\xF7\xC6\xA9\x67\xD9\x6D\xAC\x02\x11\xE2\x3A\x16\x25\xA7\x58\x08\xCB\x6F\x53\x41\x9C\x48\x38\x47\x68\x33\xD1\xD7\xC7\x8F\xD4\x74\x21\xD4\xC3\x05\x90\x7A\xFF\xCE\x96\x88\xB1\x15\x29\x5D\x23\xAB\xD0\x60\xA1\x12\x4F\xDE\xF4\x17\xCD\x32\xE5\xC9\xBF\xC8\x43\xAD\xFD\x2E\x8E\xF1\xAF\xE2\xF4\x98\xFA\x12\x1F\x20\xD8\xC0\xA7\x0C\x85\xC5\x90\xF4\x3B\x2D\x96\x26\xB1\x2C\xBE\x4C\xAB\xEB\xB1\xD2\x8A\xC9\xDB\x78\x13\x0F\x1E\x09\x9D\x6D\x8F\x00\x9F\x02\xDA\xC1\xFA\x1F\x7A\x7A\x09\xC4\x4A\xE6\x88\x2A\x97\x9F\x89\x8B\xFD\x37\x5F\x5F\x3A\xCE\x38\x59\x86\x4B\xAF\x71\x0B\xB4\xD8\xF2\x70\x4F\x9F\x32\x13\xE3\xB0\xA7\x57\xE5\xDA\xDA\x43\xCB\x84\x34\xF2\x28\xC4\xEA\x6D\xF4\x2A\xEF\xC1\x6B\x76\xDA\xFB\x7E\xBB\x85\x3C\xD2\x53\xC2\x4D\xBE\x71\xE1\x45\xD1\xFD\x23\x67\x0D\x13\x75\xFB\xCF\x65\x67\x22\x9D\xAE\xB0\x09\xD1\x09\xFF\x1D\x34\xBF\xFE\x23\x97\x37\xD2\x39\xFA\x3D\x0D\x06\x0B\xB4\xDB\x3B\xA3\xAB\x6F\x5C\x1D\xB6\x7E\xE8\xB3\x82\x34\xED\x06\x5C\x24", + ["CN=T-TeleSec GlobalRoot Class 2,OU=T-Systems Trust Center,O=T-Systems Enterprise Services GmbH,C=DE"] = "\x30\x82\x03\xC3\x30\x82\x02\xAB\xA0\x03\x02\x01\x02\x02\x01\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x30\x81\x82\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x2B\x30\x29\x06\x03\x55\x04\x0A\x0C\x22\x54\x2D\x53\x79\x73\x74\x65\x6D\x73\x20\x45\x6E\x74\x65\x72\x70\x72\x69\x73\x65\x20\x53\x65\x72\x76\x69\x63\x65\x73\x20\x47\x6D\x62\x48\x31\x1F\x30\x1D\x06\x03\x55\x04\x0B\x0C\x16\x54\x2D\x53\x79\x73\x74\x65\x6D\x73\x20\x54\x72\x75\x73\x74\x20\x43\x65\x6E\x74\x65\x72\x31\x25\x30\x23\x06\x03\x55\x04\x03\x0C\x1C\x54\x2D\x54\x65\x6C\x65\x53\x65\x63\x20\x47\x6C\x6F\x62\x61\x6C\x52\x6F\x6F\x74\x20\x43\x6C\x61\x73\x73\x20\x32\x30\x1E\x17\x0D\x30\x38\x31\x30\x30\x31\x31\x30\x34\x30\x31\x34\x5A\x17\x0D\x33\x33\x31\x30\x30\x31\x32\x33\x35\x39\x35\x39\x5A\x30\x81\x82\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x2B\x30\x29\x06\x03\x55\x04\x0A\x0C\x22\x54\x2D\x53\x79\x73\x74\x65\x6D\x73\x20\x45\x6E\x74\x65\x72\x70\x72\x69\x73\x65\x20\x53\x65\x72\x76\x69\x63\x65\x73\x20\x47\x6D\x62\x48\x31\x1F\x30\x1D\x06\x03\x55\x04\x0B\x0C\x16\x54\x2D\x53\x79\x73\x74\x65\x6D\x73\x20\x54\x72\x75\x73\x74\x20\x43\x65\x6E\x74\x65\x72\x31\x25\x30\x23\x06\x03\x55\x04\x03\x0C\x1C\x54\x2D\x54\x65\x6C\x65\x53\x65\x63\x20\x47\x6C\x6F\x62\x61\x6C\x52\x6F\x6F\x74\x20\x43\x6C\x61\x73\x73\x20\x32\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\xAA\x5F\xDA\x1B\x5F\xE8\x73\x91\xE5\xDA\x5C\xF4\xA2\xE6\x47\xE5\xF3\x68\x55\x60\x05\x1D\x02\xA4\xB3\x9B\x59\xF3\x1E\x8A\xAF\x34\xAD\xFC\x0D\xC2\xD9\x48\x19\xEE\x69\x8F\xC9\x20\xFC\x21\xAA\x07\x19\xED\xB0\x5C\xAC\x65\xC7\x5F\xED\x02\x7C\x7B\x7C\x2D\x1B\xD6\xBA\xB9\x80\xC2\x18\x82\x16\x84\xFA\x66\xB0\x08\xC6\x54\x23\x81\xE4\xCD\xB9\x49\x3F\xF6\x4F\x6E\x37\x48\x28\x38\x0F\xC5\xBE\xE7\x68\x70\xFD\x39\x97\x4D\xD2\xC7\x98\x91\x50\xAA\xC4\x44\xB3\x23\x7D\x39\x47\xE9\x52\x62\xD6\x12\x93\x5E\xB7\x31\x96\x42\x05\xFB\x76\xA7\x1E\xA3\xF5\xC2\xFC\xE9\x7A\xC5\x6C\xA9\x71\x4F\xEA\xCB\x78\xBC\x60\xAF\xC7\xDE\xF4\xD9\xCB\xBE\x7E\x33\xA5\x6E\x94\x83\xF0\x34\xFA\x21\xAB\xEA\x8E\x72\xA0\x3F\xA4\xDE\x30\x5B\xEF\x86\x4D\x6A\x95\x5B\x43\x44\xA8\x10\x15\x1C\xE5\x01\x57\xC5\x98\xF1\xE6\x06\x28\x91\xAA\x20\xC5\xB7\x53\x26\x51\x43\xB2\x0B\x11\x95\x58\xE1\xC0\x0F\x76\xD9\xC0\x8D\x7C\x81\xF3\x72\x70\x9E\x6F\xFE\x1A\x8E\xD9\x5F\x35\xC6\xB2\x6F\x34\x7C\xBE\x48\x4F\xE2\x5A\x39\xD7\xD8\x9D\x78\x9E\x9F\x86\x3E\x03\x5E\x19\x8B\x44\xA2\xD5\xC7\x02\x03\x01\x00\x01\xA3\x42\x30\x40\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xBF\x59\x20\x36\x00\x79\xA0\xA0\x22\x6B\x8C\xD5\xF2\x61\xD2\xB8\x2C\xCB\x82\x4A\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x03\x82\x01\x01\x00\x31\x03\xA2\x61\x0B\x1F\x74\xE8\x72\x36\xC6\x6D\xF9\x4D\x9E\xFA\x22\xA8\xE1\x81\x56\xCF\xCD\xBB\x9F\xEA\xAB\x91\x19\x38\xAF\xAA\x7C\x15\x4D\xF3\xB6\xA3\x8D\xA5\xF4\x8E\xF6\x44\xA9\xA7\xE8\x21\x95\xAD\x3E\x00\x62\x16\x88\xF0\x02\xBA\xFC\x61\x23\xE6\x33\x9B\x30\x7A\x6B\x36\x62\x7B\xAD\x04\x23\x84\x58\x65\xE2\xDB\x2B\x8A\xE7\x25\x53\x37\x62\x53\x5F\xBC\xDA\x01\x62\x29\xA2\xA6\x27\x71\xE6\x3A\x22\x7E\xC1\x6F\x1D\x95\x70\x20\x4A\x07\x34\xDF\xEA\xFF\x15\x80\xE5\xBA\xD7\x7A\xD8\x5B\x75\x7C\x05\x7A\x29\x47\x7E\x40\xA8\x31\x13\x77\xCD\x40\x3B\xB4\x51\x47\x7A\x2E\x11\xE3\x47\x11\xDE\x9D\x66\xD0\x8B\xD5\x54\x66\xFA\x83\x55\xEA\x7C\xC2\x29\x89\x1B\xE9\x6F\xB3\xCE\xE2\x05\x84\xC9\x2F\x3E\x78\x85\x62\x6E\xC9\x5F\xC1\x78\x63\x74\x58\xC0\x48\x18\x0C\x99\x39\xEB\xA4\xCC\x1A\xB5\x79\x5A\x8D\x15\x9C\xD8\x14\x0D\xF6\x7A\x07\x57\xC7\x22\x83\x05\x2D\x3C\x9B\x25\x26\x3D\x18\xB3\xA9\x43\x7C\xC8\xC8\xAB\x64\x8F\x0E\xA3\xBF\x9C\x1B\x9D\x30\xDB\xDA\xD0\x19\x2E\xAA\x3C\xF1\xFB\x33\x80\x76\xE4\xCD\xAD\x19\x4F\x05\x27\x8E\x13\xA1\x6E\xC2", + ["C=DE,O=Atos,CN=Atos TrustedRoot 2011"] = "\x30\x82\x03\x77\x30\x82\x02\x5F\xA0\x03\x02\x01\x02\x02\x08\x5C\x33\xCB\x62\x2C\x5F\xB3\x32\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x30\x3C\x31\x1E\x30\x1C\x06\x03\x55\x04\x03\x0C\x15\x41\x74\x6F\x73\x20\x54\x72\x75\x73\x74\x65\x64\x52\x6F\x6F\x74\x20\x32\x30\x31\x31\x31\x0D\x30\x0B\x06\x03\x55\x04\x0A\x0C\x04\x41\x74\x6F\x73\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x30\x1E\x17\x0D\x31\x31\x30\x37\x30\x37\x31\x34\x35\x38\x33\x30\x5A\x17\x0D\x33\x30\x31\x32\x33\x31\x32\x33\x35\x39\x35\x39\x5A\x30\x3C\x31\x1E\x30\x1C\x06\x03\x55\x04\x03\x0C\x15\x41\x74\x6F\x73\x20\x54\x72\x75\x73\x74\x65\x64\x52\x6F\x6F\x74\x20\x32\x30\x31\x31\x31\x0D\x30\x0B\x06\x03\x55\x04\x0A\x0C\x04\x41\x74\x6F\x73\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x30\x82\x01\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x00\x30\x82\x01\x0A\x02\x82\x01\x01\x00\x95\x85\x3B\x97\x6F\x2A\x3B\x2E\x3B\xCF\xA6\xF3\x29\x35\xBE\xCF\x18\xAC\x3E\xAA\xD9\xF8\x4D\xA0\x3E\x1A\x47\xB9\xBC\x9A\xDF\xF2\xFE\xCC\x3E\x47\xE8\x7A\x96\xC2\x24\x8E\x35\xF4\xA9\x0C\xFC\x82\xFD\x6D\xC1\x72\x62\x27\xBD\xEA\x6B\xEB\xE7\x8A\xCC\x54\x3E\x90\x50\xCF\x80\xD4\x95\xFB\xE8\xB5\x82\xD4\x14\xC5\xB6\xA9\x55\x25\x57\xDB\xB1\x50\xF6\xB0\x60\x64\x59\x7A\x69\xCF\x03\xB7\x6F\x0D\xBE\xCA\x3E\x6F\x74\x72\xEA\xAA\x30\x2A\x73\x62\xBE\x49\x91\x61\xC8\x11\xFE\x0E\x03\x2A\xF7\x6A\x20\xDC\x02\x15\x0D\x5E\x15\x6A\xFC\xE3\x82\xC1\xB5\xC5\x9D\x64\x09\x6C\xA3\x59\x98\x07\x27\xC7\x1B\x96\x2B\x61\x74\x71\x6C\x43\xF1\xF7\x35\x89\x10\xE0\x9E\xEC\x55\xA1\x37\x22\xA2\x87\x04\x05\x2C\x47\x7D\xB4\x1C\xB9\x62\x29\x66\x28\xCA\xB7\xE1\x93\xF5\xA4\x94\x03\x99\xB9\x70\x85\xB5\xE6\x48\xEA\x8D\x50\xFC\xD9\xDE\xCC\x6F\x07\x0E\xDD\x0B\x72\x9D\x80\x30\x16\x07\x95\x3F\x28\x0E\xFD\xC5\x75\x4F\x53\xD6\x74\x9A\xB4\x24\x2E\x8E\x02\x91\xCF\x76\xC5\x9B\x1E\x55\x74\x9C\x78\x21\xB1\xF0\x2D\xF1\x0B\x9F\xC2\xD5\x96\x18\x1F\xF0\x54\x22\x7A\x8C\x07\x02\x03\x01\x00\x01\xA3\x7D\x30\x7B\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xA7\xA5\x06\xB1\x2C\xA6\x09\x60\xEE\xD1\x97\xE9\x70\xAE\xBC\x3B\x19\x6C\xDB\x21\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\xA7\xA5\x06\xB1\x2C\xA6\x09\x60\xEE\xD1\x97\xE9\x70\xAE\xBC\x3B\x19\x6C\xDB\x21\x30\x18\x06\x03\x55\x1D\x20\x04\x11\x30\x0F\x30\x0D\x06\x0B\x2B\x06\x01\x04\x01\xB0\x2D\x03\x04\x01\x01\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x86\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x03\x82\x01\x01\x00\x26\x77\x34\xDB\x94\x48\x86\x2A\x41\x9D\x2C\x3E\x06\x90\x60\xC4\x8C\xAC\x0B\x54\xB8\x1F\xB9\x7B\xD3\x07\x39\xE4\xFA\x3E\x7B\xB2\x3D\x4E\xED\x9F\x23\xBD\x97\xF3\x6B\x5C\xEF\xEE\xFD\x40\xA6\xDF\xA1\x93\xA1\x0A\x86\xAC\xEF\x20\xD0\x79\x01\xBD\x78\xF7\x19\xD8\x24\x31\x34\x04\x01\xA6\xBA\x15\x9A\xC3\x27\xDC\xD8\x4F\x0F\xCC\x18\x63\xFF\x99\x0F\x0E\x91\x6B\x75\x16\xE1\x21\xFC\xD8\x26\xC7\x47\xB7\xA6\xCF\x58\x72\x71\x7E\xBA\xE1\x4D\x95\x47\x3B\xC9\xAF\x6D\xA1\xB4\xC1\xEC\x89\xF6\xB4\x0F\x38\xB5\xE2\x64\xDC\x25\xCF\xA6\xDB\xEB\x9A\x5C\x99\xA1\xC5\x08\xDE\xFD\xE6\xDA\xD5\xD6\x5A\x45\x0C\xC4\xB7\xC2\xB5\x14\xEF\xB4\x11\xFF\x0E\x15\xB5\xF5\xF5\xDB\xC6\xBD\xEB\x5A\xA7\xF0\x56\x22\xA9\x3C\x65\x54\xC6\x15\xA8\xBD\x86\x9E\xCD\x83\x96\x68\x7A\x71\x81\x89\xE1\x0B\xE1\xEA\x11\x1B\x68\x08\xCC\x69\x9E\xEC\x9E\x41\x9E\x44\x32\x26\x7A\xE2\x87\x0A\x71\x3D\xEB\xE4\x5A\xA4\xD2\xDB\xC5\xCD\xC6\xDE\x60\x7F\xB9\xF3\x4F\x44\x92\xEF\x2A\xB7\x18\x3E\xA7\x19\xD9\x0B\x7D\xB1\x37\x41\x42\xB0\xBA\x60\x1D\xF2\xFE\x09\x11\xB0\xF0\x87\x7B\xA7\x9D", }; From 2be0cb210ad437992507203e7802c8012d981f34 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Fri, 28 Feb 2014 15:26:35 -0800 Subject: [PATCH 098/254] Updating CHANGES and VERSION. --- CHANGES | 4 ++++ NEWS | 2 ++ VERSION | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 3b5c29cdc8..f2ec3ef3a5 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,8 @@ +2.2-194 | 2014-02-28 14:50:53 -0800 + + * Remove packet sorter. Addresses BIT-700. (Bernhard Amann) + 2.2-192 | 2014-02-28 09:46:43 -0800 * Update Mozilla root bundle. (Bernhard Amann) diff --git a/NEWS b/NEWS index 9b87de3e41..54ee916d5b 100644 --- a/NEWS +++ b/NEWS @@ -47,6 +47,8 @@ Changed Functionality TODO: Update if we add a detector for filtered traces. +- We have removed the packet sorter component. + Bro 2.2 ======= diff --git a/VERSION b/VERSION index df4bb3a595..c133a83bd4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2-192 +2.2-194 From ffd219e3b0739ebc0c55158d54cb16642a253ac3 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Fri, 28 Feb 2014 15:28:20 -0800 Subject: [PATCH 099/254] Updating submodule(s). [nomail] --- aux/broctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/broctl b/aux/broctl index 5e1a917880..07349a4593 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit 5e1a917880143ec824ffbe1ffaa6fc176c47b611 +Subproject commit 07349a459372d72b333bbc50e5f70584520c0bb3 From f2f817c8b15bf104904390d6abd38a0e5c33f53e Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Fri, 28 Feb 2014 15:36:58 -0800 Subject: [PATCH 100/254] Forgot to remove test code when merging. --- CHANGES | 4 ++++ VERSION | 2 +- src/PktSrc.cc | 6 ------ 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/CHANGES b/CHANGES index f2ec3ef3a5..4cb4ad82c0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,8 @@ +2.2-197 | 2014-02-28 15:36:58 -0800 + + * Remove test code. (Robin Sommer) + 2.2-194 | 2014-02-28 14:50:53 -0800 * Remove packet sorter. Addresses BIT-700. (Bernhard Amann) diff --git a/VERSION b/VERSION index c133a83bd4..90e2bd5d51 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2-194 +2.2-197 diff --git a/src/PktSrc.cc b/src/PktSrc.cc index 528f10f92c..b5ac3a5d69 100644 --- a/src/PktSrc.cc +++ b/src/PktSrc.cc @@ -220,12 +220,6 @@ void PktSrc::Process() break; } - case DLT_IEEE802_11: - { - printf("Here\n"); - exit(0); - } - case DLT_EN10MB: { // Get protocol being carried from the ethernet frame. From 338d521003c66531b53dfe84755e2b3479d88d32 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Sun, 2 Mar 2014 13:52:32 -0800 Subject: [PATCH 101/254] Fixing removal of support analyzers, plus some tweaking and cleanup of CONNECT code. Removal of support analyzers was broken. The code now actually doesn't delete them immediately anymore but instead just flags them as disabled. They'll be destroyed with the parent analyzer later. Also includes a new leak tests exercising the CONNECT code. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch topic/robin/http-connect # Changes to be committed: # modified: scripts/base/protocols/http/main.bro # modified: scripts/base/protocols/ssl/consts.bro # modified: src/analyzer/Analyzer.cc # modified: src/analyzer/Analyzer.h # modified: src/analyzer/protocol/http/HTTP.cc # new file: testing/btest/core/leaks/http-connect.bro # modified: testing/btest/scripts/base/protocols/http/http-connect.bro # # Untracked files: # .tags # changes.txt # conn.log # debug.log # diff # mpls-in-vlan.patch # newfile.pcap # packet_filter.log # reporter.log # src/PktSrc.cc.orig # weird.log # --- scripts/base/protocols/http/main.bro | 2 +- scripts/base/protocols/ssl/consts.bro | 1 + src/analyzer/Analyzer.cc | 114 ++++++++++-------- src/analyzer/Analyzer.h | 29 ++++- src/analyzer/protocol/http/HTTP.cc | 26 ++-- testing/btest/core/leaks/http-connect.bro | 14 +++ .../base/protocols/http/http-connect.bro | 7 +- 7 files changed, 128 insertions(+), 65 deletions(-) create mode 100644 testing/btest/core/leaks/http-connect.bro diff --git a/scripts/base/protocols/http/main.bro b/scripts/base/protocols/http/main.bro index 27257be2d6..ed20bc6586 100644 --- a/scripts/base/protocols/http/main.bro +++ b/scripts/base/protocols/http/main.bro @@ -218,7 +218,7 @@ event http_reply(c: connection, version: string, code: count, reason: string) &p c$http$info_code = code; c$http$info_msg = reason; } - + if ( c$http?$method && c$http$method == "CONNECT" && code == 200 ) { # Copy this conn_id and set the orig_p to zero because in the case of CONNECT proxies there will diff --git a/scripts/base/protocols/ssl/consts.bro b/scripts/base/protocols/ssl/consts.bro index 55289a7419..b81aebfbbb 100644 --- a/scripts/base/protocols/ssl/consts.bro +++ b/scripts/base/protocols/ssl/consts.bro @@ -86,6 +86,7 @@ export { [13172] = "next_protocol_negotiation", [13175] = "origin_bound_certificates", [13180] = "encrypted_client_certificates", + [30031] = "channel_id", [65281] = "renegotiation_info" } &default=function(i: count):string { return fmt("unknown-%d", i); }; diff --git a/src/analyzer/Analyzer.cc b/src/analyzer/Analyzer.cc index 03734f1a22..63462c0049 100644 --- a/src/analyzer/Analyzer.cc +++ b/src/analyzer/Analyzer.cc @@ -209,11 +209,11 @@ void Analyzer::NextPacket(int len, const u_char* data, bool is_orig, int seq, if ( skip ) return; - // If we have support analyzers, we pass it to them. - if ( is_orig && orig_supporters ) - orig_supporters->NextPacket(len, data, is_orig, seq, ip, caplen); - else if ( ! is_orig && resp_supporters ) - resp_supporters->NextPacket(len, data, is_orig, seq, ip, caplen); + SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig); + + if ( next_sibling ) + next_sibling->NextPacket(len, data, is_orig, seq, ip, caplen); + else { try @@ -232,11 +232,11 @@ void Analyzer::NextStream(int len, const u_char* data, bool is_orig) if ( skip ) return; - // If we have support analyzers, we pass it to them. - if ( is_orig && orig_supporters ) - orig_supporters->NextStream(len, data, is_orig); - else if ( ! is_orig && resp_supporters ) - resp_supporters->NextStream(len, data, is_orig); + SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig); + + if ( next_sibling ) + next_sibling->NextStream(len, data, is_orig); + else { try @@ -255,11 +255,11 @@ void Analyzer::NextUndelivered(int seq, int len, bool is_orig) if ( skip ) return; - // If we have support analyzers, we pass it to them. - if ( is_orig && orig_supporters ) - orig_supporters->NextUndelivered(seq, len, is_orig); - else if ( ! is_orig && resp_supporters ) - resp_supporters->NextUndelivered(seq, len, is_orig); + SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig); + + if ( next_sibling ) + next_sibling->NextUndelivered(seq, len, is_orig); + else { try @@ -278,11 +278,10 @@ void Analyzer::NextEndOfData(bool is_orig) if ( skip ) return; - // If we have support analyzers, we pass it to them. - if ( is_orig && orig_supporters ) - orig_supporters->NextEndOfData(is_orig); - else if ( ! is_orig && resp_supporters ) - resp_supporters->NextEndOfData(is_orig); + SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig); + + if ( next_sibling ) + next_sibling->NextEndOfData(is_orig); else EndOfData(is_orig); } @@ -558,31 +557,17 @@ void Analyzer::AddSupportAnalyzer(SupportAnalyzer* analyzer) void Analyzer::RemoveSupportAnalyzer(SupportAnalyzer* analyzer) { - SupportAnalyzer** head = - analyzer->IsOrig() ? &orig_supporters : &resp_supporters; - - SupportAnalyzer* prev = 0; - SupportAnalyzer* s; - for ( s = *head; s && s != analyzer; prev = s, s = s->sibling ) - ; - - if ( ! s ) - return; - - if ( prev ) - prev->sibling = s->sibling; - else - *head = s->sibling; - - DBG_LOG(DBG_ANALYZER, "%s removed support %s", + DBG_LOG(DBG_ANALYZER, "%s disabled %s support analyzer %s", fmt_analyzer(this).c_str(), analyzer->IsOrig() ? "originator" : "responder", fmt_analyzer(analyzer).c_str()); - if ( ! analyzer->finished ) - analyzer->Done(); - - delete analyzer; + // We mark the analyzer as being removed here, which will prevent it + // from being used further. However, we don't actually delete it + // before the parent gets destroyed. While we woulc do that, it's a + // bit tricky to do at the right time and it doesn't seem worth the + // trouble. + analyzer->removing = true; return; } @@ -596,6 +581,19 @@ bool Analyzer::HasSupportAnalyzer(Tag tag, bool orig) return false; } +SupportAnalyzer* Analyzer::FirstSupportAnalyzer(bool orig) + { + SupportAnalyzer* sa = orig ? orig_supporters : resp_supporters; + + if ( ! sa ) + return 0; + + if ( ! sa->Removing() ) + return sa; + + return sa->Sibling(true); + } + void Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, int seq, const IP_Hdr* ip, int caplen) { @@ -782,16 +780,32 @@ void Analyzer::Weird(const char* name, const char* addl) conn->Weird(name, addl); } +SupportAnalyzer* SupportAnalyzer::Sibling(bool only_active) const + { + if ( ! only_active ) + return sibling; + + SupportAnalyzer* next = sibling; + while ( next && next->Removing() ) + next = next->sibling; + + return next; + } + void SupportAnalyzer::ForwardPacket(int len, const u_char* data, bool is_orig, int seq, const IP_Hdr* ip, int caplen) { // We do not call parent's method, as we're replacing the functionality. + if ( GetOutputHandler() ) GetOutputHandler()->DeliverPacket(len, data, is_orig, seq, ip, caplen); - else if ( sibling ) + + SupportAnalyzer* next_sibling = Sibling(true); + + if ( next_sibling ) // Pass to next in chain. - sibling->NextPacket(len, data, is_orig, seq, ip, caplen); + next_sibling->NextPacket(len, data, is_orig, seq, ip, caplen); else // Finished with preprocessing - now it's the parent's turn. Parent()->DeliverPacket(len, data, is_orig, seq, ip, caplen); @@ -800,12 +814,15 @@ void SupportAnalyzer::ForwardPacket(int len, const u_char* data, bool is_orig, void SupportAnalyzer::ForwardStream(int len, const u_char* data, bool is_orig) { // We do not call parent's method, as we're replacing the functionality. + if ( GetOutputHandler() ) GetOutputHandler()->DeliverStream(len, data, is_orig); - else if ( sibling ) + SupportAnalyzer* next_sibling = Sibling(true); + + if ( next_sibling ) // Pass to next in chain. - sibling->NextStream(len, data, is_orig); + next_sibling->NextStream(len, data, is_orig); else // Finished with preprocessing - now it's the parent's turn. Parent()->DeliverStream(len, data, is_orig); @@ -814,12 +831,15 @@ void SupportAnalyzer::ForwardStream(int len, const u_char* data, bool is_orig) void SupportAnalyzer::ForwardUndelivered(int seq, int len, bool is_orig) { // We do not call parent's method, as we're replacing the functionality. + if ( GetOutputHandler() ) GetOutputHandler()->Undelivered(seq, len, is_orig); - else if ( sibling ) + SupportAnalyzer* next_sibling = Sibling(true); + + if ( next_sibling ) // Pass to next in chain. - sibling->NextUndelivered(seq, len, is_orig); + next_sibling->NextUndelivered(seq, len, is_orig); else // Finished with preprocessing - now it's the parent's turn. Parent()->Undelivered(seq, len, is_orig); diff --git a/src/analyzer/Analyzer.h b/src/analyzer/Analyzer.h index f7ca07ca51..578020082b 100644 --- a/src/analyzer/Analyzer.h +++ b/src/analyzer/Analyzer.h @@ -587,7 +587,7 @@ protected: void RemoveTimer(Timer* t); /** - * Returnsn true if the analyzer has associated an SupportAnalyzer of a given type. + * Returns true if the analyzer has associated an SupportAnalyzer of a given type. * * @param tag The type to check for. * @@ -595,6 +595,14 @@ protected: */ bool HasSupportAnalyzer(Tag tag, bool orig); + /** + * Returns the first still active support analyzer for the given + * direction, or null if none. + * + * @param orig True if asking about the originator side. + */ + SupportAnalyzer* FirstSupportAnalyzer(bool orig); + /** * Adds a a new child analyzer with the option whether to intialize * it. This is an internal method. @@ -616,6 +624,12 @@ protected: */ void AppendNewChildren(); + /** + * Returns true if the analyzer has been flagged for removal and + * shouldn't be used otherwise anymore. + */ + bool Removing() const { return removing; } + private: // Internal method to eventually delete a child analyzer that's // already Done(). @@ -718,6 +732,14 @@ public: */ bool IsOrig() const { return orig; } + /** + * Returns the analyzer's next sibling, or null if none. + * + * only_active: If true, this will skip siblings that are still link + * but flagged for removal. + */ + SupportAnalyzer* Sibling(bool only_active = false) const; + /** * Passes packet input to the next sibling SupportAnalyzer if any, or * on to the associated main analyzer if none. If however there's an @@ -749,11 +771,6 @@ public: */ virtual void ForwardUndelivered(int seq, int len, bool orig); - /** - * Returns the analyzer next sibling, or null if none. - */ - SupportAnalyzer* Sibling() const { return sibling; } - protected: friend class Analyzer; diff --git a/src/analyzer/protocol/http/HTTP.cc b/src/analyzer/protocol/http/HTTP.cc index 93dbfbcb2e..0d49bb037f 100644 --- a/src/analyzer/protocol/http/HTTP.cc +++ b/src/analyzer/protocol/http/HTTP.cc @@ -950,7 +950,7 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) if ( pia ) { - // There will be a PIA instance if this connection has been identified + // There will be a PIA instance if this connection has been identified // as a connect proxy. ForwardStream(len, data, is_orig); return; @@ -1066,14 +1066,10 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) HTTP_Reply(); - InitHTTPMessage(content_line, - reply_message, is_orig, - ExpectReplyMessageBody(), - len); - if ( connect_request && reply_code == 200 ) { pia = new pia::PIA_TCP(Conn()); + if ( AddChildAnalyzer(pia) ) { pia->FirstPacket(true, 0); @@ -1084,13 +1080,22 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) // need to be removed. RemoveSupportAnalyzer(content_line_orig); RemoveSupportAnalyzer(content_line_resp); + + return; } + else { + // Shouldn't really happen. + delete pia; pia = 0; } } + InitHTTPMessage(content_line, + reply_message, is_orig, + ExpectReplyMessageBody(), + len); } else { @@ -1422,6 +1427,12 @@ void HTTP_Analyzer::HTTP_Request() { ProtocolConfirmation(); + const char* method = (const char*) request_method->AsString()->Bytes(); + int method_len = request_method->AsString()->Len(); + + if ( strcasecmp_n(method_len, method, "CONNECT") == 0 ) + connect_request = true; + if ( http_request ) { val_list* vl = new val_list; @@ -1436,9 +1447,6 @@ void HTTP_Analyzer::HTTP_Request() // DEBUG_MSG("%.6f http_request\n", network_time); ConnectionEvent(http_request, vl); } - - if ( strcasecmp_n(request_method->AsString()->Len(), (const char*) (request_method->AsString()->Bytes()), "CONNECT") == 0 ) - connect_request = true; } void HTTP_Analyzer::HTTP_Reply() diff --git a/testing/btest/core/leaks/http-connect.bro b/testing/btest/core/leaks/http-connect.bro new file mode 100644 index 0000000000..e9a47d00a2 --- /dev/null +++ b/testing/btest/core/leaks/http-connect.bro @@ -0,0 +1,14 @@ +# Needs perftools support. +# +# @TEST-GROUP: leaks +# +# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks +# +# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -b -m -r $TRACES/http/connect-with-smtp.trace %INPUT +# @TEST-EXEC: btest-bg-wait 15 + +@load base/protocols/conn +@load base/protocols/http +@load base/protocols/smtp +@load base/protocols/tunnels +@load base/frameworks/dpd diff --git a/testing/btest/scripts/base/protocols/http/http-connect.bro b/testing/btest/scripts/base/protocols/http/http-connect.bro index d8157e2c49..7073d88ac2 100644 --- a/testing/btest/scripts/base/protocols/http/http-connect.bro +++ b/testing/btest/scripts/base/protocols/http/http-connect.bro @@ -6,6 +6,9 @@ # @TEST-EXEC: btest-diff smtp.log # @TEST-EXEC: btest-diff tunnel.log -# The base analysis scripts are loaded by default. -#@load base/protocols/http +@load base/protocols/conn +@load base/protocols/http +@load base/protocols/smtp +@load base/protocols/tunnels +@load base/frameworks/dpd From ac9c44afd872d0ac837871723f2b8ae0a7042415 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Sun, 2 Mar 2014 13:57:10 -0800 Subject: [PATCH 102/254] Updating submodule(s). [nomail] --- aux/broctl | 2 +- src/3rdparty | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aux/broctl b/aux/broctl index 66793ec3c6..07349a4593 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit 66793ec3c602439e235bee705b654aefb7ac8dec +Subproject commit 07349a459372d72b333bbc50e5f70584520c0bb3 diff --git a/src/3rdparty b/src/3rdparty index 42a4c9694a..e96d95a130 160000 --- a/src/3rdparty +++ b/src/3rdparty @@ -1 +1 @@ -Subproject commit 42a4c9694a2b2677b050fbb7cbae26bc5ec4605a +Subproject commit e96d95a130a572b611fe70b3c3ede2b4727aaa22 From d0f8edb2a4affa843918afc568a4b040d308560a Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Tue, 11 Feb 2014 15:30:22 -0500 Subject: [PATCH 103/254] Expanding the HTTP methods used in the signature to detect HTTP traffic. --- scripts/base/protocols/http/dpd.sig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/base/protocols/http/dpd.sig b/scripts/base/protocols/http/dpd.sig index 13470f4e95..3e264f0bb3 100644 --- a/scripts/base/protocols/http/dpd.sig +++ b/scripts/base/protocols/http/dpd.sig @@ -1,6 +1,8 @@ +# List of HTTP headers pulled from: +# http://annevankesteren.nl/2007/10/http-methods signature dpd_http_client { ip-proto == tcp - payload /^[[:space:]]*(GET|HEAD|POST)[[:space:]]*/ + payload /^[[:space:]]*(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT|PROPFIND|PROPPATCH|MKCOL|COPY|MOVE|LOCK|UNLOCK|VERSION-CONTROL|REPORT|CHECKOUT|CHECKIN|UNCHECKOUT|MKWORKSPACE|UPDATE|LABEL|MERGE|BASELINE-CONTROL|MKACTIVITY|ORDERPATCH|ACL|PATCH|SEARCH|BCOPY|BDELETE|BMOVE|BPROPFIND|BPROPPATCH|NOTIFY|POLL|SUBSCRIBE|UNSUBSCRIBE|X-MS-ENUMATTS|RPC_OUT_DATA|RPC_IN_DATA)[[:space:]]*/ tcp-state originator } @@ -11,3 +13,5 @@ signature dpd_http_server { requires-reverse-signature dpd_http_client enable "http" } + + From 0f4c7080cc81e9bc66168d6612b80b3af7b54514 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 3 Mar 2014 07:09:38 -0800 Subject: [PATCH 104/254] HTTP fix for output handlers. Had broken that with the CONNECT change. --- src/analyzer/Analyzer.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/analyzer/Analyzer.cc b/src/analyzer/Analyzer.cc index 63462c0049..b280cbb6f8 100644 --- a/src/analyzer/Analyzer.cc +++ b/src/analyzer/Analyzer.cc @@ -798,8 +798,11 @@ void SupportAnalyzer::ForwardPacket(int len, const u_char* data, bool is_orig, // We do not call parent's method, as we're replacing the functionality. if ( GetOutputHandler() ) + { GetOutputHandler()->DeliverPacket(len, data, is_orig, seq, ip, caplen); + return; + } SupportAnalyzer* next_sibling = Sibling(true); @@ -816,7 +819,10 @@ void SupportAnalyzer::ForwardStream(int len, const u_char* data, bool is_orig) // We do not call parent's method, as we're replacing the functionality. if ( GetOutputHandler() ) + { GetOutputHandler()->DeliverStream(len, data, is_orig); + return; + } SupportAnalyzer* next_sibling = Sibling(true); @@ -833,7 +839,10 @@ void SupportAnalyzer::ForwardUndelivered(int seq, int len, bool is_orig) // We do not call parent's method, as we're replacing the functionality. if ( GetOutputHandler() ) + { GetOutputHandler()->Undelivered(seq, len, is_orig); + return; + } SupportAnalyzer* next_sibling = Sibling(true); From a1f2ab34ac6781d1eb1eb6ca94bb48cbc8312a4a Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Mon, 3 Mar 2014 10:49:28 -0800 Subject: [PATCH 105/254] Add verify functionality, including the ability to get the validated chain. This means that it is now possible to get information about the root-certificates that were used to secure a connection. Intermediate commit before changing the script interface again. addresses BIT-953, BIT-760 --- scripts/base/files/x509/main.bro | 11 +- scripts/base/init-bare.bro | 18 +- src/Type.h | 13 ++ src/file_analysis/analyzer/x509/X509.cc | 55 +++--- src/file_analysis/analyzer/x509/X509.h | 11 +- src/file_analysis/analyzer/x509/events.bif | 8 +- src/file_analysis/analyzer/x509/functions.bif | 171 ++++++++++++++++++ src/file_analysis/analyzer/x509/types.bif | 2 +- 8 files changed, 249 insertions(+), 40 deletions(-) create mode 100644 src/file_analysis/analyzer/x509/functions.bif diff --git a/scripts/base/files/x509/main.bro b/scripts/base/files/x509/main.bro index d19327f07c..7f7ff3064a 100644 --- a/scripts/base/files/x509/main.bro +++ b/scripts/base/files/x509/main.bro @@ -5,24 +5,27 @@ module X509; export { redef enum Log::ID += { LOG }; + + redef record Files::Info += { + }; } -event x509_cert(f: fa_file, cert: X509::Certificate) +event x509_cert(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate) { print cert; } -event x509_extension(f: fa_file, cert: X509::Certificate, ext: X509::Extension) +event x509_extension(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, ext: X509::Extension) { print ext; } -event x509_ext_basic_constraints(f: fa_file, cert: X509::Certificate, ext: X509::BasicConstraints) +event x509_ext_basic_constraints(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, ext: X509::BasicConstraints) { print ext; } -event x509_ext_subject_alternative_name(f: fa_file, cert: X509::Certificate, ext: X509::SubjectAlternativeName) +event x509_ext_subject_alternative_name(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, ext: string_vec) { print ext; } diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index e4c1803fcb..12b056a541 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -46,6 +46,13 @@ type index_vec: vector of count; ## directly and then remove this alias. type string_vec: vector of string; +## A vector of x509 opaques. +## +## .. todo:: We need this type definition only for declaring builtin functions +## via ``bifcl``. We should extend ``bifcl`` to understand composite types +## directly and then remove this alias. +type x509_opaque_vector: vector of opaque of x509; + ## A vector of addresses. ## ## .. todo:: We need this type definition only for declaring builtin functions @@ -2744,7 +2751,6 @@ export { module X509; export { type X509::Certificate: record { - certificate: opaque of x509; ##< OpenSSL certificate reference version: count; ##< Version number. serial: string; ##< Serial number. subject: string; ##< Subject. @@ -2774,8 +2780,14 @@ export { path_len: count &optional; }; - type X509::SubjectAlternativeName: record { - names: vector of string; + ## Result of an X509 certificate chain verification + type X509::Result: record { + ## OpenSSL result code + result: count; + ## Result as string + result_string: string; + ## References to the final certificate chain, if verification successful. End-host certificate is first. + chain_certs: vector of opaque of x509 &optional; }; } diff --git a/src/Type.h b/src/Type.h index 742b933ec1..323938d4c5 100644 --- a/src/Type.h +++ b/src/Type.h @@ -73,6 +73,7 @@ class EnumType; class Serializer; class VectorType; class TypeType; +class OpaqueType; const int DOES_NOT_MATCH_INDEX = 0; const int MATCHES_INDEX_SCALAR = 1; @@ -204,6 +205,18 @@ public: return (VectorType*) this; } + OpaqueType* AsOpaqueType() + { + CHECK_TYPE_TAG(TYPE_OPAQUE, "BroType::AsOpaqueType"); + return (OpaqueType*) this; + } + + const OpaqueType* AsOpaqueType() const + { + CHECK_TYPE_TAG(TYPE_OPAQUE, "BroType::AsOpaqueType"); + return (OpaqueType*) this; + } + VectorType* AsVectorType() { CHECK_TYPE_TAG(TYPE_VECTOR, "BroType::AsVectorType"); diff --git a/src/file_analysis/analyzer/x509/X509.cc b/src/file_analysis/analyzer/x509/X509.cc index 684f4f54ba..a254188585 100644 --- a/src/file_analysis/analyzer/x509/X509.cc +++ b/src/file_analysis/analyzer/x509/X509.cc @@ -49,7 +49,17 @@ bool file_analysis::X509::EndOfFile() return false; } - RecordVal* cert_record = ParseCertificate(ssl_cert); // cert_record takes ownership of ssl_cert + X509Val* cert_val = new X509Val(ssl_cert); // cert_val takes ownership of ssl_cert + + RecordVal* cert_record = ParseCertificate(cert_val); // parse basic information into record + + // and send the record on to scriptland + val_list* vl = new val_list(); + vl->append(GetFile()->GetVal()->Ref()); + vl->append(cert_val->Ref()); + vl->append(cert_record->Ref()); // we Ref it here, because we want to keep a copy around for now... + + mgr.QueueEvent(x509_cert, vl); // after parsing the certificate - parse the extensions... @@ -60,7 +70,7 @@ bool file_analysis::X509::EndOfFile() if ( !ex ) continue; - ParseExtension(ex, cert_record); + ParseExtension(ex, cert_record, cert_val); } // X509_free(ssl_cert); We do _not_ free the certificate here. It is refcounted @@ -69,34 +79,36 @@ bool file_analysis::X509::EndOfFile() // The certificate will be freed when the last X509Val is Unref'd. Unref(cert_record); // Unref the RecordVal that we kept around from ParseCertificate + Unref(cert_val); // Same for cert_val return false; } -RecordVal* file_analysis::X509::ParseCertificate(::X509* ssl_cert) +RecordVal* file_analysis::X509::ParseCertificate(X509Val* cert_val) { + ::X509* ssl_cert = cert_val->GetCertificate(); + char buf[256]; // we need a buffer for some of the openssl functions memset(buf, 0, 256); RecordVal* pX509Cert = new RecordVal(BifType::Record::X509::Certificate); BIO *bio = BIO_new(BIO_s_mem()); - pX509Cert->Assign(0, new X509Val(ssl_cert)); // take ownership for cleanup - pX509Cert->Assign(1, new Val((uint64) X509_get_version(ssl_cert), TYPE_COUNT)); + pX509Cert->Assign(0, new Val((uint64) X509_get_version(ssl_cert), TYPE_COUNT)); i2a_ASN1_INTEGER(bio, X509_get_serialNumber(ssl_cert)); int len = BIO_read(bio, &(*buf), sizeof buf); - pX509Cert->Assign(2, new StringVal(len, buf)); + pX509Cert->Assign(1, new StringVal(len, buf)); X509_NAME_print_ex(bio, X509_get_subject_name(ssl_cert), 0, XN_FLAG_RFC2253); len = BIO_gets(bio, &(*buf), sizeof buf); - pX509Cert->Assign(3, new StringVal(len, buf)); + pX509Cert->Assign(2, new StringVal(len, buf)); X509_NAME_print_ex(bio, X509_get_issuer_name(ssl_cert), 0, XN_FLAG_RFC2253); len = BIO_gets(bio, &(*buf), sizeof buf); - pX509Cert->Assign(4, new StringVal(len, buf)); + pX509Cert->Assign(3, new StringVal(len, buf)); BIO_free(bio); - pX509Cert->Assign(5, new Val(get_time_from_asn1(X509_get_notBefore(ssl_cert)), TYPE_TIME)); - pX509Cert->Assign(6, new Val(get_time_from_asn1(X509_get_notAfter(ssl_cert)), TYPE_TIME)); + pX509Cert->Assign(4, new Val(get_time_from_asn1(X509_get_notBefore(ssl_cert)), TYPE_TIME)); + pX509Cert->Assign(5, new Val(get_time_from_asn1(X509_get_notAfter(ssl_cert)), TYPE_TIME)); // we only read 255 bytes because byte 256 is always 0. // if the string is longer than 255, that will be our null-termination, @@ -141,16 +153,11 @@ RecordVal* file_analysis::X509::ParseCertificate(::X509* ssl_cert) pX509Cert->Assign(9, new Val(length, TYPE_COUNT)); } - val_list* vl = new val_list(); - vl->append(GetFile()->GetVal()->Ref()); - vl->append(pX509Cert->Ref()); // we Ref it here, because we want to keep a copy around for now... - - mgr.QueueEvent(x509_cert, vl); return pX509Cert; } -void file_analysis::X509::ParseExtension(X509_EXTENSION* ex, RecordVal* r) +void file_analysis::X509::ParseExtension(X509_EXTENSION* ex, RecordVal* r, X509Val* cert_val) { char name[256]; char oid[256]; @@ -196,6 +203,7 @@ void file_analysis::X509::ParseExtension(X509_EXTENSION* ex, RecordVal* r) // but I am not sure if there is a better way to do it... val_list* vl = new val_list(); vl->append(GetFile()->GetVal()->Ref()); + vl->append(cert_val->Ref()); vl->append(r->Ref()); vl->append(pX509Ext); @@ -203,12 +211,12 @@ void file_analysis::X509::ParseExtension(X509_EXTENSION* ex, RecordVal* r) // look if we have a specialized handler for this event... if ( OBJ_obj2nid(ext_asn) == NID_basic_constraints ) - ParseBasicConstraints(ex, r); + ParseBasicConstraints(ex, r, cert_val); else if ( OBJ_obj2nid(ext_asn) == NID_subject_alt_name ) - ParseSAN(ex, r); + ParseSAN(ex, r, cert_val); } -void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r) +void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r, X509Val* cert_val) { assert(OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == NID_basic_constraints); @@ -226,6 +234,7 @@ void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r } val_list* vl = new val_list(); vl->append(GetFile()->GetVal()->Ref()); + vl->append(cert_val->Ref()); vl->append(r->Ref()); vl->append(pBasicConstraint); @@ -234,7 +243,7 @@ void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r } } -void file_analysis::X509::ParseSAN(X509_EXTENSION* ext, RecordVal* r) +void file_analysis::X509::ParseSAN(X509_EXTENSION* ext, RecordVal* r, X509Val* cert_val) { assert(OBJ_obj2nid(X509_EXTENSION_get_object(ext)) == NID_subject_alt_name); @@ -273,13 +282,11 @@ void file_analysis::X509::ParseSAN(X509_EXTENSION* ext, RecordVal* r) } } - RecordVal* pSan = new RecordVal(BifType::Record::X509::SubjectAlternativeName); - pSan->Assign(0, names); - val_list* vl = new val_list(); vl->append(GetFile()->GetVal()->Ref()); + vl->append(cert_val->Ref()); vl->append(r->Ref()); - vl->append(pSan); + vl->append(names); mgr.QueueEvent(x509_ext_basic_constraints, vl); } diff --git a/src/file_analysis/analyzer/x509/X509.h b/src/file_analysis/analyzer/x509/X509.h index f64aa3eb58..b535ebe256 100644 --- a/src/file_analysis/analyzer/x509/X509.h +++ b/src/file_analysis/analyzer/x509/X509.h @@ -12,12 +12,16 @@ namespace file_analysis { +class X509Val; + class X509 : public file_analysis::Analyzer { public: //~X509(); static file_analysis::Analyzer* Instantiate(RecordVal* args, File* file) { return new X509(args, file); } + + static RecordVal* ParseCertificate(X509Val* cert_val); virtual bool DeliverStream(const u_char* data, uint64 len); virtual bool Undelivered(uint64 offset, uint64 len); @@ -31,10 +35,9 @@ private: static StringVal* key_curve(EVP_PKEY *key); static unsigned int key_length(EVP_PKEY *key); - RecordVal* ParseCertificate(::X509* ssl_cert); - void ParseExtension(X509_EXTENSION* ex, RecordVal* r); - void ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r); - void ParseSAN(X509_EXTENSION* ex, RecordVal* r); + void ParseExtension(X509_EXTENSION* ex, RecordVal* r, X509Val* cert_val); + void ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r, X509Val* cert_val); + void ParseSAN(X509_EXTENSION* ex, RecordVal* r, X509Val* cert_val); std::string cert_data; }; diff --git a/src/file_analysis/analyzer/x509/events.bif b/src/file_analysis/analyzer/x509/events.bif index 2787746e0c..b78f819e90 100644 --- a/src/file_analysis/analyzer/x509/events.bif +++ b/src/file_analysis/analyzer/x509/events.bif @@ -1,4 +1,4 @@ -event x509_cert%(f: fa_file, cert: X509::Certificate%); -event x509_extension%(f: fa_file, cert: X509::Certificate, ext: X509::Extension%); -event x509_ext_basic_constraints%(f: fa_file, cert: X509::Certificate, ext: X509::BasicConstraints%); -event x509_ext_subject_alternative_name%(f: fa_file, cert: X509::Certificate, ext: X509::SubjectAlternativeName%); +event x509_cert%(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate%); +event x509_extension%(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, ext: X509::Extension%); +event x509_ext_basic_constraints%(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, ext: X509::BasicConstraints%); +event x509_ext_subject_alternative_name%(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, names: string_vec%); diff --git a/src/file_analysis/analyzer/x509/functions.bif b/src/file_analysis/analyzer/x509/functions.bif new file mode 100644 index 0000000000..7af8883aef --- /dev/null +++ b/src/file_analysis/analyzer/x509/functions.bif @@ -0,0 +1,171 @@ +%%{ +#include "file_analysis/analyzer/x509/X509.h" +#include "types.bif.h" + +#include +#include +#include + +// This is the indexed map of X509 certificate stores. +static map x509_stores; + +// ### NOTE: while d2i_X509 does not take a const u_char** pointer, +// here we assume d2i_X509 does not write to , so it is safe to +// convert data to a non-const pointer. Could some X509 guru verify +// this? + +X509* d2i_X509_(X509** px, const u_char** in, int len) + { +#ifdef OPENSSL_D2I_X509_USES_CONST_CHAR + return d2i_X509(px, in, len); +#else + return d2i_X509(px, (u_char**)in, len); +#endif + } + +%%} + +## Parses a certificate into an X509::Certificate structure +## +## cert: The x509 certificicate opaque +## +## Returns: A X509::Certificate structure +## +## .. bro:see:: x509_verify +function x509_parse%(cert: opaque of x509%): X509::Certificate + %{ + assert(cert); + file_analysis::X509Val* h = (file_analysis::X509Val*) cert; + + return file_analysis::X509::ParseCertificate(h); + %} + +## Verifies a certificate. +## +## cert_val: The X.509 certificate in DER format. +## +## cert_stack: Specifies a certificate chain that is being used to validate +## the given certificate against the root store given in *root_certs* +## +## root_certs: A list of root certificates to validate the certificate chain +## +## Returns: A record of type X509::Result containing the result code of the verify +## operation. In case of success also returns the full certificate chain. +## +## .. bro:see:: x509_parse +function x509_verify%(cert_val: opaque of x509, cert_stack: x509_opaque_vector, root_certs: table_string_of_string%): X509::Result + %{ + X509_STORE* ctx = 0; + int i = 0; + + // If this certificate store was built previously, just reuse the old one. + if ( x509_stores.count(root_certs) > 0 ) + ctx = x509_stores[root_certs]; + + if ( ! ctx ) // lookup to see if we have this one built already! + { + ctx = X509_STORE_new(); + TableVal* root_certs2 = root_certs->AsTableVal(); + ListVal* idxs = root_certs2->ConvertToPureList(); + + // Build the validation store + for ( i = 0; i < idxs->Length(); ++i ) + { + Val* key = idxs->Index(i); + StringVal *sv = root_certs2->Lookup(key)->AsStringVal(); + const uint8* data = sv->Bytes(); + X509* x = d2i_X509_(NULL, &data, sv->Len()); + if ( ! x ) + { + builtin_error(fmt("Root CA error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); + return new Val((uint64) ERR_get_error(), TYPE_COUNT); + } + X509_STORE_add_cert(ctx, x); + } + delete idxs; + + // Save the newly constructed certificate store into the cacheing map. + x509_stores[root_certs] = ctx; + } + + assert(cert_val); + file_analysis::X509Val* cert_handle = (file_analysis::X509Val*) cert_val; + + X509* cert = cert_handle->GetCertificate(); + if ( ! cert ) + { + builtin_error(fmt("No certificate in opaque")); + return new Val(-1, TYPE_COUNT); + } + + STACK_OF(X509)* untrusted_certs = sk_X509_new_null(); + if ( ! untrusted_certs ) + { + builtin_error(fmt("Untrusted certificate stack initialization error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); + return new Val((uint64) ERR_get_error(), TYPE_COUNT); + } + + VectorVal *cert_stack_vec = cert_stack->AsVectorVal(); + for ( i = 0; i < (int) cert_stack_vec->Size(); ++i ) + { + Val *sv = cert_stack_vec->Lookup(i); + // Fixme: check type + X509* x = ((file_analysis::X509Val*) sv)->GetCertificate(); + if ( ! x ) + { + sk_X509_pop(untrusted_certs); + builtin_error(fmt("No certificate in opaque in stack")); + return new Val(-1, TYPE_COUNT); + } + sk_X509_push(untrusted_certs, x); + } + + X509_STORE_CTX csc; + X509_STORE_CTX_init(&csc, ctx, cert, untrusted_certs); + X509_STORE_CTX_set_time(&csc, 0, (time_t) network_time); + + int result = X509_verify_cert(&csc); + + VectorVal* chainVector = 0; + if ( result == 1 ) // we have a valid chain. try to get it... + { + STACK_OF(X509)* chain = X509_STORE_CTX_get1_chain(&csc); // get1 = deep copy + + if (!chain) + { + reporter->Error("Encountered valid chain that could not be resolved"); + goto x509_verify_chainerror; + } + + int num_certs = sk_X509_num(chain); + chainVector = new VectorVal(new VectorType(base_type(TYPE_OPAQUE))); + + for ( int i = 0; i < num_certs; i++ ) + { + X509* currcert = sk_X509_value(chain, i); + if ( !currcert ) + { + reporter->InternalError("OpenSSL returned null certificate"); + goto x509_verify_chainerror; + } + + chainVector->Assign(i, new file_analysis::X509Val(currcert)); // X509Val takes ownership + } + } + +x509_verify_chainerror: + + X509_STORE_CTX_cleanup(&csc); + + if ( untrusted_certs ) + sk_X509_pop(untrusted_certs); + + RecordVal* rrecord = new RecordVal(BifType::Record::X509::Result); + + rrecord->Assign(0, new Val((uint64) csc.error, TYPE_COUNT)); + rrecord->Assign(1, new StringVal(X509_verify_cert_error_string(csc.error))); + if ( chainVector ) + rrecord->Assign(2, chainVector); + + return rrecord; + %} diff --git a/src/file_analysis/analyzer/x509/types.bif b/src/file_analysis/analyzer/x509/types.bif index 49a915c7fc..6b3049883e 100644 --- a/src/file_analysis/analyzer/x509/types.bif +++ b/src/file_analysis/analyzer/x509/types.bif @@ -1,5 +1,5 @@ type X509::Certificate: record; type X509::Extension: record; type X509::BasicConstraints: record; -type X509::SubjectAlternativeName: record; +type X509::Result: record; From 110d9fbd6a79020a77b6f84b7f3289835e023c33 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Mon, 3 Mar 2014 17:07:50 -0800 Subject: [PATCH 106/254] X509 file analyzer nearly done. Verification and most other policy scripts work fine now. Todo: * update all baselines * fix the circular reference to the fa_file structure I introduced :) Sadly this does not seem to be entirely straightforward. addresses BIT-953, BIT-760 --- scripts/base/files/x509/README | 1 + scripts/base/files/x509/main.bro | 77 +++++++++++---- scripts/base/init-bare.bro | 4 +- scripts/base/init-default.bro | 4 +- scripts/base/protocols/ssl/files.bro | 76 +++++++++++++-- scripts/base/protocols/ssl/main.bro | 32 +------ .../policy/frameworks/intel/seen/__load__.bro | 3 +- scripts/policy/frameworks/intel/seen/ssl.bro | 21 ----- .../frameworks/intel/seen/where-locations.bro | 3 +- scripts/policy/frameworks/intel/seen/x509.bro | 16 ++++ scripts/policy/protocols/ssl/cert-hash.bro | 22 ----- .../policy/protocols/ssl/expiring-certs.bro | 22 ++--- .../protocols/ssl/extract-certs-pem.bro | 31 ++---- scripts/policy/protocols/ssl/known-certs.bro | 20 ++-- scripts/policy/protocols/ssl/notary.bro | 9 +- .../policy/protocols/ssl/validate-certs.bro | 29 +++--- src/file_analysis/analyzer/x509/X509.cc | 22 ++--- src/file_analysis/analyzer/x509/X509.h | 6 +- src/file_analysis/analyzer/x509/events.bif | 8 +- src/file_analysis/analyzer/x509/functions.bif | 94 +++++++++++++++---- 20 files changed, 303 insertions(+), 197 deletions(-) create mode 100644 scripts/base/files/x509/README create mode 100644 scripts/policy/frameworks/intel/seen/x509.bro delete mode 100644 scripts/policy/protocols/ssl/cert-hash.bro diff --git a/scripts/base/files/x509/README b/scripts/base/files/x509/README new file mode 100644 index 0000000000..8b50366cd2 --- /dev/null +++ b/scripts/base/files/x509/README @@ -0,0 +1 @@ +Support for X509 certificates with the file analysis framework. diff --git a/scripts/base/files/x509/main.bro b/scripts/base/files/x509/main.bro index 7f7ff3064a..2238cf0c8b 100644 --- a/scripts/base/files/x509/main.bro +++ b/scripts/base/files/x509/main.bro @@ -1,32 +1,77 @@ - @load base/frameworks/files +@load base/files/hash module X509; export { redef enum Log::ID += { LOG }; - redef record Files::Info += { + type Info: record { + ## current timestamp + ts: time &log &default=network_time(); + + ## file id of this certificate + id: string &log; + + ## Basic information about the certificate + certificate: X509::Certificate &log; + + ## The opaque wrapping the certificate. Mainly used + ## for the verify operations + handle: opaque of x509; + + ## All extensions that were encountered in the certificate + extensions: vector of X509::Extension &default=vector(); + + ## Subject alternative name extension of the certificate + san: string_vec &optional &log; + + ## Basic constraints extension of the certificate + basic_constraints: X509::BasicConstraints &optional &log; }; + + ## Event for accessing logged records. + global log_x509: event(rec: Info); } -event x509_cert(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate) +event bro_init() &priority=5 { - print cert; + Log::create_stream(X509::LOG, [$columns=Info, $ev=log_x509]); } -event x509_extension(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, ext: X509::Extension) -{ -print ext; -} +redef record fa_file += { + ## Information about X509 certificates. This is used to keep + ## certificate information until all events have been received. + x509: X509::Info &optional; +}; -event x509_ext_basic_constraints(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, ext: X509::BasicConstraints) -{ -print ext; -} +event x509_certificate(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate) &priority=5 + { + f$x509 = [$id=f$id, $certificate=cert, $handle=cert_ref]; + } -event x509_ext_subject_alternative_name(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, ext: string_vec) -{ -print ext; -} +event x509_extension(f: fa_file, ext: X509::Extension) &priority=5 + { + if ( f?$x509 ) + f$x509$extensions[|f$x509$extensions|] = ext; + } +event x509_ext_basic_constraints(f: fa_file, ext: X509::BasicConstraints) &priority=5 + { + if ( f?$x509 ) + f$x509$basic_constraints = ext; + } + +event x509_ext_subject_alternative_name(f: fa_file, names: string_vec) &priority=5 + { + if ( f?$x509 ) + f$x509$san = names; + } + +event file_state_remove(f: fa_file) + { + if ( f?$x509 ) + { + Log::write(LOG, f$x509); + } + } diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 12b056a541..f59355895d 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2765,7 +2765,7 @@ export { curve: string &optional; ##< curve, if EC-certificate #ca: bool &optional; ##< indicates the CA value in the X509v3 BasicConstraints extension #path_len: count &optional; ##< indicates the path_length value in the X509v3 BasicConstraints extension - }; + } &log; type X509::Extension: record { name: string; ##< long name of extension. oid if name not known @@ -2778,7 +2778,7 @@ export { type X509::BasicConstraints: record { ca: bool; ##< CA flag set? path_len: count &optional; - }; + } &log; ## Result of an X509 certificate chain verification type X509::Result: record { diff --git a/scripts/base/init-default.bro b/scripts/base/init-default.bro index b4dca043c0..91f1157811 100644 --- a/scripts/base/init-default.bro +++ b/scripts/base/init-default.bro @@ -38,6 +38,9 @@ @load base/frameworks/sumstats @load base/frameworks/tunnels +# needed for the SSL protocol +@load base/files/x509 + @load base/protocols/conn @load base/protocols/dhcp @load base/protocols/dnp3 @@ -57,7 +60,6 @@ @load base/files/hash @load base/files/extract @load base/files/unified2 -@load base/files/x509 @load base/misc/find-checksum-offloading @load base/misc/find-filtered-trace diff --git a/scripts/base/protocols/ssl/files.bro b/scripts/base/protocols/ssl/files.bro index 7582a428ae..a8e755e953 100644 --- a/scripts/base/protocols/ssl/files.bro +++ b/scripts/base/protocols/ssl/files.bro @@ -6,9 +6,33 @@ module SSL; export { redef record Info += { - ## An ordered vector of file unique IDs which contains - ## all the certificates sent over the connection - fuids: vector of string &log &default=string_vec(); + ## Chain of certificates offered by the server to validate its + ## complete signing chain. + cert_chain: vector of fa_file &optional; + + ## An ordered vector of all certicate file unique IDs for the + ## certificates offered by the server. + cert_chain_fuids: vector of string &optional &log; + + ## Chain of certificates offered by the client to validate its + ## complete signing chain. + client_cert_chain: vector of fa_file &optional; + + ## An ordered vector of all certicate file unique IDs for the + ## certificates offered by the client. + client_cert_chain_fuids: vector of string &optional &log; + + ## 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: string &log &optional; + + ## Subject of the X.509 certificate offered by the client. + client_subject: string &log &optional; + ## Subject of the signer of the X.509 certificate offered by the + ## client. + client_issuer: string &log &optional; }; ## Default file handle provider for SSL. @@ -20,7 +44,7 @@ export { function get_file_handle(c: connection, is_orig: bool): string { - return cat(Analyzer::ANALYZER_SMTP, c$start_time); + return cat(Analyzer::ANALYZER_SSL, c$start_time); } function describe_file(f: fa_file): string @@ -29,6 +53,8 @@ function describe_file(f: fa_file): string if ( f$source != "SSL" ) return ""; + # Fixme! + return ""; } @@ -41,8 +67,46 @@ event bro_init() &priority=5 event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5 { - if ( c?$ssl ) - c$ssl$fuids[|c$ssl$fuids|] = f$id; + if ( ! c?$ssl ) + return; + + if ( ! c$ssl?$cert_chain ) + { + c$ssl$cert_chain = vector(); + c$ssl$client_cert_chain = vector(); + c$ssl$cert_chain_fuids = string_vec(); + c$ssl$client_cert_chain_fuids = string_vec(); + } + + if ( is_orig ) + { + c$ssl$client_cert_chain[|c$ssl$client_cert_chain|] = f; + c$ssl$client_cert_chain_fuids[|c$ssl$client_cert_chain_fuids|] = f$id; + } + else + { + c$ssl$cert_chain[|c$ssl$cert_chain|] = f; + c$ssl$cert_chain_fuids[|c$ssl$cert_chain_fuids|] = f$id; + } Files::add_analyzer(f, Files::ANALYZER_X509); + # always calculate hashes for certificates + Files::add_analyzer(f, Files::ANALYZER_MD5); + Files::add_analyzer(f, Files::ANALYZER_SHA1); + } + +event ssl_established(c: connection) &priority=6 + { + # update subject and issuer information + if ( c$ssl?$cert_chain && |c$ssl$cert_chain| > 0 ) + { + c$ssl$subject = c$ssl$cert_chain[0]$x509$certificate$subject; + c$ssl$issuer = c$ssl$cert_chain[0]$x509$certificate$issuer; + } + + if ( c$ssl?$client_cert_chain && |c$ssl$client_cert_chain| > 0 ) + { + c$ssl$client_subject = c$ssl$client_cert_chain[0]$x509$certificate$subject; + c$ssl$client_issuer = c$ssl$client_cert_chain[0]$x509$certificate$issuer; + } } diff --git a/scripts/base/protocols/ssl/main.bro b/scripts/base/protocols/ssl/main.bro index be62cf419d..e803077d19 100644 --- a/scripts/base/protocols/ssl/main.bro +++ b/scripts/base/protocols/ssl/main.bro @@ -24,36 +24,9 @@ export { server_name: string &log &optional; ## Session ID offered by the client for session resumption. 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 server certificate. - not_valid_after: time &log &optional; ## Last alert that was seen during the connection. last_alert: string &log &optional; - ## Subject of the X.509 certificate offered by the client. - client_subject: string &log &optional; - ## Subject of the signer of the X.509 certificate offered by the - ## client. - client_issuer_subject: string &log &optional; - - ## Full binary server certificate stored in DER format. - cert: string &optional; - ## Chain of certificates offered by the server to validate its - ## complete signing chain. - cert_chain: vector of string &optional; - - ## Full binary client certificate stored in DER format. - client_cert: string &optional; - ## Chain of certificates offered by the client to validate its - ## complete signing chain. - client_cert_chain: vector of string &optional; - ## The analyzer ID used for the analyzer instance attached ## to each connection. It is not used for logging since it's a ## meaningless arbitrary number. @@ -108,8 +81,7 @@ event bro_init() &priority=5 function set_session(c: connection) { if ( ! c?$ssl ) - c$ssl = [$ts=network_time(), $uid=c$uid, $id=c$id, $cert_chain=vector(), - $client_cert_chain=vector()]; + c$ssl = [$ts=network_time(), $uid=c$uid, $id=c$id]; } function delay_log(info: Info, token: string) @@ -185,7 +157,7 @@ event ssl_alert(c: connection, is_orig: bool, level: count, desc: count) &priori c$ssl$last_alert = alert_descriptions[desc]; } -event ssl_established(c: connection) &priority=5 +event ssl_established(c: connection) &priority=7 { set_session(c); } diff --git a/scripts/policy/frameworks/intel/seen/__load__.bro b/scripts/policy/frameworks/intel/seen/__load__.bro index 01034d95e2..807bf0fcb2 100644 --- a/scripts/policy/frameworks/intel/seen/__load__.bro +++ b/scripts/policy/frameworks/intel/seen/__load__.bro @@ -6,4 +6,5 @@ @load ./http-url @load ./ssl @load ./smtp -@load ./smtp-url-extraction \ No newline at end of file +@load ./smtp-url-extraction +@load ./x509 diff --git a/scripts/policy/frameworks/intel/seen/ssl.bro b/scripts/policy/frameworks/intel/seen/ssl.bro index e404c39e5b..c41dbbdbe1 100644 --- a/scripts/policy/frameworks/intel/seen/ssl.bro +++ b/scripts/policy/frameworks/intel/seen/ssl.bro @@ -2,27 +2,6 @@ @load base/protocols/ssl @load ./where-locations -event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) - { - if ( chain_idx == 0 ) - { - if ( /emailAddress=/ in cert$subject ) - { - local email = sub(cert$subject, /^.*emailAddress=/, ""); - email = sub(email, /,.*$/, ""); - Intel::seen([$indicator=email, - $indicator_type=Intel::EMAIL, - $conn=c, - $where=(is_orig ? SSL::IN_CLIENT_CERT : SSL::IN_SERVER_CERT)]); - } - - Intel::seen([$indicator=sha1_hash(der_cert), - $indicator_type=Intel::CERT_HASH, - $conn=c, - $where=(is_orig ? SSL::IN_CLIENT_CERT : SSL::IN_SERVER_CERT)]); - } - } - event ssl_extension(c: connection, is_orig: bool, code: count, val: string) { if ( is_orig && SSL::extensions[code] == "server_name" && diff --git a/scripts/policy/frameworks/intel/seen/where-locations.bro b/scripts/policy/frameworks/intel/seen/where-locations.bro index 0387814ea7..b9b4325bc1 100644 --- a/scripts/policy/frameworks/intel/seen/where-locations.bro +++ b/scripts/policy/frameworks/intel/seen/where-locations.bro @@ -21,9 +21,8 @@ export { SMTP::IN_REPLY_TO, SMTP::IN_X_ORIGINATING_IP_HEADER, SMTP::IN_MESSAGE, - SSL::IN_SERVER_CERT, - SSL::IN_CLIENT_CERT, SSL::IN_SERVER_NAME, SMTP::IN_HEADER, + X509::IN_CERT, }; } diff --git a/scripts/policy/frameworks/intel/seen/x509.bro b/scripts/policy/frameworks/intel/seen/x509.bro new file mode 100644 index 0000000000..de6c0ab495 --- /dev/null +++ b/scripts/policy/frameworks/intel/seen/x509.bro @@ -0,0 +1,16 @@ +@load base/frameworks/intel +@load base/files/x509 +@load ./where-locations + +event x509_certificate(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate) + { + if ( /emailAddress=/ in cert$subject ) + { + local email = sub(cert$subject, /^.*emailAddress=/, ""); + email = sub(email, /,.*$/, ""); + Intel::seen([$indicator=email, + $indicator_type=Intel::EMAIL, + $f=f, + $where=X509::IN_CERT]); + } + } diff --git a/scripts/policy/protocols/ssl/cert-hash.bro b/scripts/policy/protocols/ssl/cert-hash.bro deleted file mode 100644 index 32a165a946..0000000000 --- a/scripts/policy/protocols/ssl/cert-hash.bro +++ /dev/null @@ -1,22 +0,0 @@ -##! Calculate MD5 sums for server DER formatted certificates. - -@load base/protocols/ssl - -module SSL; - -export { - redef record Info += { - ## MD5 sum of the raw server certificate. - cert_hash: string &log &optional; - }; -} - -event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) &priority=4 - { - # We aren't tracking client certificates yet and we are also only tracking - # the primary cert. Watch that this came from an SSL analyzed session too. - if ( is_orig || chain_idx != 0 || ! c?$ssl ) - return; - - c$ssl$cert_hash = md5_hash(der_cert); - } \ No newline at end of file diff --git a/scripts/policy/protocols/ssl/expiring-certs.bro b/scripts/policy/protocols/ssl/expiring-certs.bro index be6526877b..fc48ad9f2b 100644 --- a/scripts/policy/protocols/ssl/expiring-certs.bro +++ b/scripts/policy/protocols/ssl/expiring-certs.bro @@ -3,10 +3,7 @@ ##! certificate. @load base/protocols/ssl -@load base/frameworks/notice -@load base/utils/directions-and-hosts - -@load protocols/ssl/cert-hash +@load base/files/x509 module SSL; @@ -35,30 +32,31 @@ export { const notify_when_cert_expiring_in = 30days &redef; } -event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) &priority=3 +event ssl_established(c: connection) &priority=3 { - # If this isn't the host cert or we aren't interested in the server, just return. - if ( is_orig || - chain_idx != 0 || - ! c$ssl?$cert_hash || + # If there are no certificates or we are not interested in the server, just return. + if ( ! c$ssl?$cert_chain || |c$ssl$cert_chain| == 0 || ! addr_matches_host(c$id$resp_h, notify_certs_expiration) ) return; + + local hash = c$ssl$cert_chain[0]$info$md5; + local cert = c$ssl$cert_chain[0]$x509$certificate; if ( cert$not_valid_before > network_time() ) NOTICE([$note=Certificate_Not_Valid_Yet, $conn=c, $suppress_for=1day, $msg=fmt("Certificate %s isn't valid until %T", cert$subject, cert$not_valid_before), - $identifier=cat(c$id$resp_h, c$id$resp_p, c$ssl$cert_hash)]); + $identifier=cat(c$id$resp_h, c$id$resp_p, hash)]); else if ( cert$not_valid_after < network_time() ) NOTICE([$note=Certificate_Expired, $conn=c, $suppress_for=1day, $msg=fmt("Certificate %s expired at %T", cert$subject, cert$not_valid_after), - $identifier=cat(c$id$resp_h, c$id$resp_p, c$ssl$cert_hash)]); + $identifier=cat(c$id$resp_h, c$id$resp_p, hash)]); else if ( cert$not_valid_after - notify_when_cert_expiring_in < network_time() ) NOTICE([$note=Certificate_Expires_Soon, $msg=fmt("Certificate %s is going to expire at %T", cert$subject, cert$not_valid_after), $conn=c, $suppress_for=1day, - $identifier=cat(c$id$resp_h, c$id$resp_p, c$ssl$cert_hash)]); + $identifier=cat(c$id$resp_h, c$id$resp_p, hash)]); } diff --git a/scripts/policy/protocols/ssl/extract-certs-pem.bro b/scripts/policy/protocols/ssl/extract-certs-pem.bro index 32293ebef3..247d58fea2 100644 --- a/scripts/policy/protocols/ssl/extract-certs-pem.bro +++ b/scripts/policy/protocols/ssl/extract-certs-pem.bro @@ -10,8 +10,7 @@ ##! @load base/protocols/ssl -@load base/utils/directions-and-hosts -@load protocols/ssl/cert-hash +@load base/files/x509 module SSL; @@ -23,41 +22,31 @@ export { } # This is an internally maintained variable to prevent relogging of -# certificates that have already been seen. It is indexed on an md5 sum of +# certificates that have already been seen. It is indexed on an sha1 sum of # the certificate. global extracted_certs: set[string] = set() &read_expire=1hr &redef; event ssl_established(c: connection) &priority=5 { - if ( ! c$ssl?$cert ) + if ( ! c$ssl?$cert_chain || |c$ssl$cert_chain| == 0 ) return; if ( ! addr_matches_host(c$id$resp_h, extract_certs_pem) ) return; - if ( c$ssl$cert_hash in extracted_certs ) + local hash = c$ssl$cert_chain[0]$info$sha1; + local cert = c$ssl$cert_chain[0]$x509$handle; + + if ( hash in extracted_certs ) # If we already extracted this cert, don't do it again. return; - add extracted_certs[c$ssl$cert_hash]; + add extracted_certs[hash]; local filename = Site::is_local_addr(c$id$resp_h) ? "certs-local.pem" : "certs-remote.pem"; local outfile = open_for_append(filename); + enable_raw_output(outfile); - print outfile, "-----BEGIN CERTIFICATE-----"; + print outfile, x509_get_certificate_string(cert, T); - # Encode to base64 and format to fit 50 lines. Otherwise openssl won't like it later. - local lines = split_all(encode_base64(c$ssl$cert), /.{50}/); - local i = 1; - for ( line in lines ) - { - if ( |lines[i]| > 0 ) - { - print outfile, lines[i]; - } - i+=1; - } - - print outfile, "-----END CERTIFICATE-----"; - print outfile, ""; close(outfile); } diff --git a/scripts/policy/protocols/ssl/known-certs.bro b/scripts/policy/protocols/ssl/known-certs.bro index 478074f55a..e1bf59e72d 100644 --- a/scripts/policy/protocols/ssl/known-certs.bro +++ b/scripts/policy/protocols/ssl/known-certs.bro @@ -3,7 +3,7 @@ @load base/utils/directions-and-hosts @load base/protocols/ssl -@load protocols/ssl/cert-hash +@load base/files/x509 module Known; @@ -31,9 +31,9 @@ export { const cert_tracking = LOCAL_HOSTS &redef; ## The set of all known certificates to store for preventing duplicate - ## logging. It can also be used from other scripts to + ## logging. It can also be used from other scripts to ## inspect if a certificate has been seen in use. The string value - ## in the set is for storing the DER formatted certificate's MD5 hash. + ## in the set is for storing the DER formatted certificate' SHA1 hash. global certs: set[addr, string] &create_expire=1day &synchronized &redef; ## Event that can be handled to access the loggable record as it is sent @@ -46,16 +46,18 @@ event bro_init() &priority=5 Log::create_stream(Known::CERTS_LOG, [$columns=CertsInfo, $ev=log_known_certs]); } -event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) &priority=3 +event ssl_established(c: connection) &priority=3 { - # Make sure this is the server cert and we have a hash for it. - if ( is_orig || chain_idx != 0 || ! c$ssl?$cert_hash ) + if ( ! c$ssl?$cert_chain || |c$ssl$cert_chain| < 1 ) return; - + + local hash = c$ssl$cert_chain[0]$info$sha1; + local cert = c$ssl$cert_chain[0]$x509$certificate; + local host = c$id$resp_h; - if ( [host, c$ssl$cert_hash] !in certs && addr_matches_host(host, cert_tracking) ) + if ( [host, hash] !in certs && addr_matches_host(host, cert_tracking) ) { - add certs[host, c$ssl$cert_hash]; + add certs[host, hash]; Log::write(Known::CERTS_LOG, [$ts=network_time(), $host=host, $port_num=c$id$resp_p, $subject=cert$subject, $issuer_subject=cert$issuer, diff --git a/scripts/policy/protocols/ssl/notary.bro b/scripts/policy/protocols/ssl/notary.bro index 29cd655860..424959df2f 100644 --- a/scripts/policy/protocols/ssl/notary.bro +++ b/scripts/policy/protocols/ssl/notary.bro @@ -16,7 +16,6 @@ export { } redef record SSL::Info += { - sha1: string &log &optional; notary: Response &log &optional; }; @@ -38,14 +37,12 @@ function clear_waitlist(digest: string) } } -event x509_certificate(c: connection, is_orig: bool, cert: X509, - chain_idx: count, chain_len: count, der_cert: string) +event ssl_established(c: connection) &priority=3 { - if ( is_orig || chain_idx != 0 || ! c?$ssl ) + if ( ! c$ssl?$cert_chain || |c$ssl$cert_chain| == 0 ) return; - local digest = sha1_hash(der_cert); - c$ssl$sha1 = digest; + local digest = c$ssl$cert_chain[0]$info$sha1; if ( digest in notary_cache ) { diff --git a/scripts/policy/protocols/ssl/validate-certs.bro b/scripts/policy/protocols/ssl/validate-certs.bro index 886c28b6ac..de22e2d30d 100644 --- a/scripts/policy/protocols/ssl/validate-certs.bro +++ b/scripts/policy/protocols/ssl/validate-certs.bro @@ -2,7 +2,6 @@ @load base/frameworks/notice @load base/protocols/ssl -@load protocols/ssl/cert-hash module SSL; @@ -19,9 +18,9 @@ export { validation_status: string &log &optional; }; - ## MD5 hash values for recently validated certs along with the + ## MD5 hash values for recently validated chains along with the ## validation status message are kept in this table to avoid constant - ## validation every time the same certificate is seen. + ## validation every time the same certificate chain is seen. global recently_validated_certs: table[string] of string = table() &read_expire=5mins &synchronized &redef; } @@ -29,18 +28,26 @@ export { event ssl_established(c: connection) &priority=3 { # If there aren't any certs we can't very well do certificate validation. - if ( ! c$ssl?$cert || ! c$ssl?$cert_chain ) + if ( ! c$ssl?$cert_chain || |c$ssl$cert_chain| == 0 ) return; - - if ( c$ssl?$cert_hash && c$ssl$cert_hash in recently_validated_certs ) + + local chain_id = join_string_vec(c$ssl$cert_chain_fuids, "."); + + local chain: vector of opaque of x509 = vector(); + for ( i in c$ssl$cert_chain ) { - c$ssl$validation_status = recently_validated_certs[c$ssl$cert_hash]; + chain[i] = c$ssl$cert_chain[i]$x509$handle; + } + + if ( chain_id in recently_validated_certs ) + { + c$ssl$validation_status = recently_validated_certs[chain_id]; } else { - local result = x509_verify(c$ssl$cert, c$ssl$cert_chain, root_certs); - c$ssl$validation_status = x509_err2str(result); - recently_validated_certs[c$ssl$cert_hash] = c$ssl$validation_status; + local result = x509_verify(chain, root_certs); + c$ssl$validation_status = result$result_string; + recently_validated_certs[chain_id] = result$result_string; } if ( c$ssl$validation_status != "ok" ) @@ -48,7 +55,7 @@ event ssl_established(c: connection) &priority=3 local message = fmt("SSL certificate validation failed with (%s)", c$ssl$validation_status); NOTICE([$note=Invalid_Server_Cert, $msg=message, $sub=c$ssl$subject, $conn=c, - $identifier=cat(c$id$resp_h,c$id$resp_p,c$ssl$validation_status,c$ssl$cert_hash)]); + $identifier=cat(c$id$resp_h,c$id$resp_p,c$ssl$validation_status)]); } } diff --git a/src/file_analysis/analyzer/x509/X509.cc b/src/file_analysis/analyzer/x509/X509.cc index a254188585..96e0964eff 100644 --- a/src/file_analysis/analyzer/x509/X509.cc +++ b/src/file_analysis/analyzer/x509/X509.cc @@ -59,7 +59,7 @@ bool file_analysis::X509::EndOfFile() vl->append(cert_val->Ref()); vl->append(cert_record->Ref()); // we Ref it here, because we want to keep a copy around for now... - mgr.QueueEvent(x509_cert, vl); + mgr.QueueEvent(x509_certificate, vl); // after parsing the certificate - parse the extensions... @@ -70,7 +70,7 @@ bool file_analysis::X509::EndOfFile() if ( !ex ) continue; - ParseExtension(ex, cert_record, cert_val); + ParseExtension(ex); } // X509_free(ssl_cert); We do _not_ free the certificate here. It is refcounted @@ -157,7 +157,7 @@ RecordVal* file_analysis::X509::ParseCertificate(X509Val* cert_val) return pX509Cert; } -void file_analysis::X509::ParseExtension(X509_EXTENSION* ex, RecordVal* r, X509Val* cert_val) +void file_analysis::X509::ParseExtension(X509_EXTENSION* ex) { char name[256]; char oid[256]; @@ -203,20 +203,18 @@ void file_analysis::X509::ParseExtension(X509_EXTENSION* ex, RecordVal* r, X509V // but I am not sure if there is a better way to do it... val_list* vl = new val_list(); vl->append(GetFile()->GetVal()->Ref()); - vl->append(cert_val->Ref()); - vl->append(r->Ref()); vl->append(pX509Ext); mgr.QueueEvent(x509_extension, vl); // look if we have a specialized handler for this event... if ( OBJ_obj2nid(ext_asn) == NID_basic_constraints ) - ParseBasicConstraints(ex, r, cert_val); + ParseBasicConstraints(ex); else if ( OBJ_obj2nid(ext_asn) == NID_subject_alt_name ) - ParseSAN(ex, r, cert_val); + ParseSAN(ex); } -void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r, X509Val* cert_val) +void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex) { assert(OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == NID_basic_constraints); @@ -234,8 +232,6 @@ void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r } val_list* vl = new val_list(); vl->append(GetFile()->GetVal()->Ref()); - vl->append(cert_val->Ref()); - vl->append(r->Ref()); vl->append(pBasicConstraint); mgr.QueueEvent(x509_ext_basic_constraints, vl); @@ -243,7 +239,7 @@ void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r } } -void file_analysis::X509::ParseSAN(X509_EXTENSION* ext, RecordVal* r, X509Val* cert_val) +void file_analysis::X509::ParseSAN(X509_EXTENSION* ext) { assert(OBJ_obj2nid(X509_EXTENSION_get_object(ext)) == NID_subject_alt_name); @@ -284,11 +280,9 @@ void file_analysis::X509::ParseSAN(X509_EXTENSION* ext, RecordVal* r, X509Val* c val_list* vl = new val_list(); vl->append(GetFile()->GetVal()->Ref()); - vl->append(cert_val->Ref()); - vl->append(r->Ref()); vl->append(names); - mgr.QueueEvent(x509_ext_basic_constraints, vl); + mgr.QueueEvent(x509_ext_subject_alternative_name, vl); } StringVal* file_analysis::X509::key_curve(EVP_PKEY *key) diff --git a/src/file_analysis/analyzer/x509/X509.h b/src/file_analysis/analyzer/x509/X509.h index b535ebe256..6008383468 100644 --- a/src/file_analysis/analyzer/x509/X509.h +++ b/src/file_analysis/analyzer/x509/X509.h @@ -35,9 +35,9 @@ private: static StringVal* key_curve(EVP_PKEY *key); static unsigned int key_length(EVP_PKEY *key); - void ParseExtension(X509_EXTENSION* ex, RecordVal* r, X509Val* cert_val); - void ParseBasicConstraints(X509_EXTENSION* ex, RecordVal* r, X509Val* cert_val); - void ParseSAN(X509_EXTENSION* ex, RecordVal* r, X509Val* cert_val); + void ParseExtension(X509_EXTENSION* ex); + void ParseBasicConstraints(X509_EXTENSION* ex); + void ParseSAN(X509_EXTENSION* ex); std::string cert_data; }; diff --git a/src/file_analysis/analyzer/x509/events.bif b/src/file_analysis/analyzer/x509/events.bif index b78f819e90..2cfc5882a4 100644 --- a/src/file_analysis/analyzer/x509/events.bif +++ b/src/file_analysis/analyzer/x509/events.bif @@ -1,4 +1,4 @@ -event x509_cert%(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate%); -event x509_extension%(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, ext: X509::Extension%); -event x509_ext_basic_constraints%(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, ext: X509::BasicConstraints%); -event x509_ext_subject_alternative_name%(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate, names: string_vec%); +event x509_certificate%(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate%); +event x509_extension%(f: fa_file, ext: X509::Extension%); +event x509_ext_basic_constraints%(f: fa_file, ext: X509::BasicConstraints%); +event x509_ext_subject_alternative_name%(f: fa_file, names: string_vec%); diff --git a/src/file_analysis/analyzer/x509/functions.bif b/src/file_analysis/analyzer/x509/functions.bif index 7af8883aef..36c261d216 100644 --- a/src/file_analysis/analyzer/x509/functions.bif +++ b/src/file_analysis/analyzer/x509/functions.bif @@ -23,11 +23,22 @@ X509* d2i_X509_(X509** px, const u_char** in, int len) #endif } +// construct an error record +RecordVal* x509_error_record(uint64_t num, const char* reason) + { + RecordVal* rrecord = new RecordVal(BifType::Record::X509::Result); + + rrecord->Assign(0, new Val(num, TYPE_COUNT)); + rrecord->Assign(1, new StringVal(reason)); + + return rrecord; + } + %%} ## Parses a certificate into an X509::Certificate structure ## -## cert: The x509 certificicate opaque +## cert: The X509 certificicate opaque handle ## ## Returns: A X509::Certificate structure ## @@ -40,12 +51,50 @@ function x509_parse%(cert: opaque of x509%): X509::Certificate return file_analysis::X509::ParseCertificate(h); %} +## Returns the string form of a certificate +## +## cert: The X509 certificate opaque handle +## +## pem: A boolean that specifies if the certificate is returned +## in pem-form (true), or as the raw ASN1 encoded binary +## (false). +## +## Returns: X509 certificate as a string + +function x509_get_certificate_string%(cert: opaque of x509, pem: bool &default=F%): string + %{ + assert(cert); + file_analysis::X509Val* h = (file_analysis::X509Val*) cert; + + BIO *bio = BIO_new(BIO_s_mem()); + + if ( pem ) + { + PEM_write_bio_X509(bio, h->GetCertificate()); + } + else + { + i2d_X509_bio(bio, h->GetCertificate()); + } + + BIO_flush(bio); + int length = BIO_pending(bio); + // use OPENSS_malloc here. Otherwhise, interesting problems will happen + char *buffer = (char*) OPENSSL_malloc(length); + BIO_read(bio, (void*) buffer, length); + StringVal* ext_val = new StringVal(length, buffer); + OPENSSL_free(buffer); + BIO_free_all(bio); + + return ext_val; + %} + + ## Verifies a certificate. ## -## cert_val: The X.509 certificate in DER format. -## -## cert_stack: Specifies a certificate chain that is being used to validate -## the given certificate against the root store given in *root_certs* +## certs: Specifies a certificate chain that is being used to validate +## the given certificate against the root store given in *root_certs*. +## The host certificate has to be at index 0. ## ## root_certs: A list of root certificates to validate the certificate chain ## @@ -53,10 +102,27 @@ function x509_parse%(cert: opaque of x509%): X509::Certificate ## operation. In case of success also returns the full certificate chain. ## ## .. bro:see:: x509_parse -function x509_verify%(cert_val: opaque of x509, cert_stack: x509_opaque_vector, root_certs: table_string_of_string%): X509::Result +function x509_verify%(certs: x509_opaque_vector, root_certs: table_string_of_string%): X509::Result %{ X509_STORE* ctx = 0; int i = 0; + + VectorVal *certs_vec = certs->AsVectorVal(); + if ( certs_vec->Size() < 1 ) + { + reporter->Error("No certificates given in vector"); + return x509_error_record(-1, "no certificates"); + } + + // host certificate + unsigned int index = 0; // to prevent overloading to 0pointer + Val *sv = certs_vec->Lookup(index); + if ( !sv ) + { + builtin_error("undefined value in certificate vector"); + return x509_error_record(-1, "undefined value in certificate vector"); + } + file_analysis::X509Val* cert_handle = (file_analysis::X509Val*) sv; // If this certificate store was built previously, just reuse the old one. if ( x509_stores.count(root_certs) > 0 ) @@ -78,7 +144,7 @@ function x509_verify%(cert_val: opaque of x509, cert_stack: x509_opaque_vector, if ( ! x ) { builtin_error(fmt("Root CA error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); - return new Val((uint64) ERR_get_error(), TYPE_COUNT); + return x509_error_record((uint64) ERR_get_error(), ERR_error_string(ERR_peek_last_error(),NULL)); } X509_STORE_add_cert(ctx, x); } @@ -88,34 +154,30 @@ function x509_verify%(cert_val: opaque of x509, cert_stack: x509_opaque_vector, x509_stores[root_certs] = ctx; } - assert(cert_val); - file_analysis::X509Val* cert_handle = (file_analysis::X509Val*) cert_val; - X509* cert = cert_handle->GetCertificate(); if ( ! cert ) { builtin_error(fmt("No certificate in opaque")); - return new Val(-1, TYPE_COUNT); + return x509_error_record(-1, "No certificate in opaque"); } STACK_OF(X509)* untrusted_certs = sk_X509_new_null(); if ( ! untrusted_certs ) { builtin_error(fmt("Untrusted certificate stack initialization error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); - return new Val((uint64) ERR_get_error(), TYPE_COUNT); + return x509_error_record((uint64) ERR_get_error(), ERR_error_string(ERR_peek_last_error(),NULL)); } - VectorVal *cert_stack_vec = cert_stack->AsVectorVal(); - for ( i = 0; i < (int) cert_stack_vec->Size(); ++i ) + for ( i = 1; i < (int) certs_vec->Size(); ++i ) // start at 1 - 0 is host cert { - Val *sv = cert_stack_vec->Lookup(i); + Val *sv = certs_vec->Lookup(i); // Fixme: check type X509* x = ((file_analysis::X509Val*) sv)->GetCertificate(); if ( ! x ) { sk_X509_pop(untrusted_certs); builtin_error(fmt("No certificate in opaque in stack")); - return new Val(-1, TYPE_COUNT); + return x509_error_record(-1, "No certificate in opaque"); } sk_X509_push(untrusted_certs, x); } From 7eb6b5133e803411d7c97aee02456efb55ac5f18 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Tue, 4 Mar 2014 05:29:04 -0800 Subject: [PATCH 107/254] Fix circular reference problem and a few other small things. SSL::Info now holds a reference to Files::Info instead of the fa_files record. Everything should work now, if everyone thinks that the interface is ok I will update the test baselines in a bit. addresses BIT-953, BIT-760 --- scripts/base/files/x509/main.bro | 26 +++++++++---------- scripts/base/protocols/ssl/files.bro | 9 ++++--- .../policy/protocols/ssl/expiring-certs.bro | 2 +- .../protocols/ssl/extract-certs-pem.bro | 2 +- scripts/policy/protocols/ssl/known-certs.bro | 2 +- scripts/policy/protocols/ssl/notary.bro | 2 +- scripts/test-all-policy.bro | 2 +- src/file_analysis/analyzer/x509/X509.cc | 2 +- 8 files changed, 24 insertions(+), 23 deletions(-) diff --git a/scripts/base/files/x509/main.bro b/scripts/base/files/x509/main.bro index 2238cf0c8b..b20c6c715e 100644 --- a/scripts/base/files/x509/main.bro +++ b/scripts/base/files/x509/main.bro @@ -39,7 +39,7 @@ event bro_init() &priority=5 Log::create_stream(X509::LOG, [$columns=Info, $ev=log_x509]); } -redef record fa_file += { +redef record Files::Info += { ## Information about X509 certificates. This is used to keep ## certificate information until all events have been received. x509: X509::Info &optional; @@ -47,31 +47,31 @@ redef record fa_file += { event x509_certificate(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate) &priority=5 { - f$x509 = [$id=f$id, $certificate=cert, $handle=cert_ref]; + f$info$x509 = [$id=f$id, $certificate=cert, $handle=cert_ref]; } event x509_extension(f: fa_file, ext: X509::Extension) &priority=5 { - if ( f?$x509 ) - f$x509$extensions[|f$x509$extensions|] = ext; + if ( f$info?$x509 ) + f$info$x509$extensions[|f$info$x509$extensions|] = ext; } event x509_ext_basic_constraints(f: fa_file, ext: X509::BasicConstraints) &priority=5 { - if ( f?$x509 ) - f$x509$basic_constraints = ext; + if ( f$info?$x509 ) + f$info$x509$basic_constraints = ext; } event x509_ext_subject_alternative_name(f: fa_file, names: string_vec) &priority=5 { - if ( f?$x509 ) - f$x509$san = names; + if ( f$info?$x509 ) + f$info$x509$san = names; } -event file_state_remove(f: fa_file) +event file_state_remove(f: fa_file) &priority=5 { - if ( f?$x509 ) - { - Log::write(LOG, f$x509); - } + if ( ! f$info?$x509 ) + return; + + Log::write(LOG, f$info$x509); } diff --git a/scripts/base/protocols/ssl/files.bro b/scripts/base/protocols/ssl/files.bro index a8e755e953..a10a3f5f76 100644 --- a/scripts/base/protocols/ssl/files.bro +++ b/scripts/base/protocols/ssl/files.bro @@ -1,6 +1,7 @@ @load ./main @load base/utils/conn-ids @load base/frameworks/files +@load base/files/x509 module SSL; @@ -8,7 +9,7 @@ export { redef record Info += { ## Chain of certificates offered by the server to validate its ## complete signing chain. - cert_chain: vector of fa_file &optional; + cert_chain: vector of Files::Info &optional; ## An ordered vector of all certicate file unique IDs for the ## certificates offered by the server. @@ -16,7 +17,7 @@ export { ## Chain of certificates offered by the client to validate its ## complete signing chain. - client_cert_chain: vector of fa_file &optional; + client_cert_chain: vector of Files::Info &optional; ## An ordered vector of all certicate file unique IDs for the ## certificates offered by the client. @@ -80,12 +81,12 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori if ( is_orig ) { - c$ssl$client_cert_chain[|c$ssl$client_cert_chain|] = f; + c$ssl$client_cert_chain[|c$ssl$client_cert_chain|] = f$info; c$ssl$client_cert_chain_fuids[|c$ssl$client_cert_chain_fuids|] = f$id; } else { - c$ssl$cert_chain[|c$ssl$cert_chain|] = f; + c$ssl$cert_chain[|c$ssl$cert_chain|] = f$info; c$ssl$cert_chain_fuids[|c$ssl$cert_chain_fuids|] = f$id; } diff --git a/scripts/policy/protocols/ssl/expiring-certs.bro b/scripts/policy/protocols/ssl/expiring-certs.bro index fc48ad9f2b..a76dc542f4 100644 --- a/scripts/policy/protocols/ssl/expiring-certs.bro +++ b/scripts/policy/protocols/ssl/expiring-certs.bro @@ -39,7 +39,7 @@ event ssl_established(c: connection) &priority=3 ! addr_matches_host(c$id$resp_h, notify_certs_expiration) ) return; - local hash = c$ssl$cert_chain[0]$info$md5; + local hash = c$ssl$cert_chain[0]$md5; local cert = c$ssl$cert_chain[0]$x509$certificate; if ( cert$not_valid_before > network_time() ) diff --git a/scripts/policy/protocols/ssl/extract-certs-pem.bro b/scripts/policy/protocols/ssl/extract-certs-pem.bro index 247d58fea2..1cfccb6556 100644 --- a/scripts/policy/protocols/ssl/extract-certs-pem.bro +++ b/scripts/policy/protocols/ssl/extract-certs-pem.bro @@ -34,7 +34,7 @@ event ssl_established(c: connection) &priority=5 if ( ! addr_matches_host(c$id$resp_h, extract_certs_pem) ) return; - local hash = c$ssl$cert_chain[0]$info$sha1; + local hash = c$ssl$cert_chain[0]$sha1; local cert = c$ssl$cert_chain[0]$x509$handle; if ( hash in extracted_certs ) diff --git a/scripts/policy/protocols/ssl/known-certs.bro b/scripts/policy/protocols/ssl/known-certs.bro index e1bf59e72d..e0e76eb526 100644 --- a/scripts/policy/protocols/ssl/known-certs.bro +++ b/scripts/policy/protocols/ssl/known-certs.bro @@ -51,7 +51,7 @@ event ssl_established(c: connection) &priority=3 if ( ! c$ssl?$cert_chain || |c$ssl$cert_chain| < 1 ) return; - local hash = c$ssl$cert_chain[0]$info$sha1; + local hash = c$ssl$cert_chain[0]$sha1; local cert = c$ssl$cert_chain[0]$x509$certificate; local host = c$id$resp_h; diff --git a/scripts/policy/protocols/ssl/notary.bro b/scripts/policy/protocols/ssl/notary.bro index 424959df2f..3646a4d43e 100644 --- a/scripts/policy/protocols/ssl/notary.bro +++ b/scripts/policy/protocols/ssl/notary.bro @@ -42,7 +42,7 @@ event ssl_established(c: connection) &priority=3 if ( ! c$ssl?$cert_chain || |c$ssl$cert_chain| == 0 ) return; - local digest = c$ssl$cert_chain[0]$info$sha1; + local digest = c$ssl$cert_chain[0]$sha1; if ( digest in notary_cache ) { diff --git a/scripts/test-all-policy.bro b/scripts/test-all-policy.bro index 3a0bd17614..a29d2d3030 100644 --- a/scripts/test-all-policy.bro +++ b/scripts/test-all-policy.bro @@ -26,6 +26,7 @@ @load frameworks/intel/seen/smtp.bro @load frameworks/intel/seen/ssl.bro @load frameworks/intel/seen/where-locations.bro +@load frameworks/intel/seen/x509.bro @load frameworks/files/detect-MHR.bro @load frameworks/files/hash-all-files.bro @load frameworks/packet-filter/shunt.bro @@ -82,7 +83,6 @@ @load protocols/ssh/geo-data.bro @load protocols/ssh/interesting-hostnames.bro @load protocols/ssh/software.bro -@load protocols/ssl/cert-hash.bro @load protocols/ssl/expiring-certs.bro @load protocols/ssl/extract-certs-pem.bro @load protocols/ssl/known-certs.bro diff --git a/src/file_analysis/analyzer/x509/X509.cc b/src/file_analysis/analyzer/x509/X509.cc index 96e0964eff..4109781193 100644 --- a/src/file_analysis/analyzer/x509/X509.cc +++ b/src/file_analysis/analyzer/x509/X509.cc @@ -480,7 +480,7 @@ X509Val::~X509Val() bool X509Val::DoSerialize(SerialInfo* info) const { - DO_SERIALIZE(SER_X509_VAL, X509Val); + DO_SERIALIZE(SER_X509_VAL, OpaqueVal); unsigned char *buf = NULL; From b22ca5d0a3caf0f4501739abe4d111eec5e29253 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 4 Mar 2014 11:12:06 -0600 Subject: [PATCH 108/254] Replace libmagic w/ Bro signatures for file MIME type identification. Notable changes: - libmagic is no longer used at all. All MIME type detection is done through new Bro signatures, and there's no longer a means to get verbose file type descriptions (e.g. "PNG image data, 1435 x 170"). The majority of the default file magic signatures are derived from the default magic database of libmagic ~5.17. - File magic signatures consist of two new constructs in the signature rule parsing grammar: "file-magic" gives a regular expression to match against, and "file-mime" gives the MIME type string of content that matches the magic and an optional strength value for the match. - Modified signature/rule syntax for identifiers: they can no longer start with a '-', which made for ambiguous syntax when doing negative strength values in "file-mime". Also brought syntax for Bro script identifiers in line with reality (they can't start with numbers or include '-' at all). - A new Built-In Function, "file_magic", can be used to get all file magic matches and their corresponding strength against a given chunk of data - The second parameter of the "identify_data" Built-In Function can no longer be used to get verbose file type descriptions, though it can still be used to get the strongest matching file magic signature. - The "file_transferred" event's "descr" parameter no longer contains verbose file type descriptions. - The BROMAGIC environment variable no longer changes any behavior in Bro as magic databases are no longer used/installed. - Reverted back to minimum requirement of CMake 2.6.3 from 2.8.0 (it's back to being the same requirement as the Bro v2.2 release). The bump was to accomodate building libmagic as an external project, which is no longer needed. Addresses BIT-1143. --- .gitmodules | 3 - CMakeLists.txt | 39 +- doc/CMakeLists.txt | 3 - doc/frameworks/signatures.rst | 42 +- doc/install/install.rst | 2 +- magic | 1 - scripts/base/frameworks/files/__load__.bro | 1 + .../base/frameworks/files/magic/__load__.bro | 2 + .../base/frameworks/files/magic/general.sig | 11 + .../base/frameworks/files/magic/libmagic.sig | 4199 +++++++++++++++++ scripts/base/init-bare.bro | 17 + scripts/base/init-default.bro | 1 - src/CMakeLists.txt | 3 - src/NetVar.cc | 4 + src/NetVar.h | 2 + src/Rule.cc | 2 +- src/Rule.h | 2 +- src/RuleAction.cc | 5 + src/RuleAction.h | 25 + src/RuleMatcher.cc | 139 + src/RuleMatcher.h | 65 + src/analyzer/protocol/file/File.cc | 14 +- src/analyzer/protocol/file/events.bif | 11 +- src/bro.bif | 66 +- src/file_analysis/File.cc | 20 +- src/file_analysis/File.h | 5 +- src/main.cc | 8 - src/rule-parse.y | 22 +- src/rule-scan.l | 10 +- src/util-config.h.in | 1 - src/util.cc | 49 - src/util.h | 7 - testing/btest/Baseline/bifs.identify_data/out | 2 - .../canonified_loaded_scripts.log | 5 +- .../canonified_loaded_scripts.log | 5 +- .../btest-doc.sphinx.file_extraction#1 | 2 +- .../btest-doc.sphinx.mimestats#1 | 8 +- .../out | 2 +- .../c.out | 2 +- testing/btest/bifs/identify_data.bro | 2 - 40 files changed, 4636 insertions(+), 173 deletions(-) delete mode 160000 magic create mode 100644 scripts/base/frameworks/files/magic/__load__.bro create mode 100644 scripts/base/frameworks/files/magic/general.sig create mode 100644 scripts/base/frameworks/files/magic/libmagic.sig diff --git a/.gitmodules b/.gitmodules index 87826d2ef6..4998cc6b80 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,9 +16,6 @@ [submodule "cmake"] path = cmake url = git://git.bro.org/cmake -[submodule "magic"] - path = magic - url = git://git.bro.org/bromagic [submodule "src/3rdparty"] path = src/3rdparty url = git://git.bro.org/bro-3rdparty diff --git a/CMakeLists.txt b/CMakeLists.txt index f773381ae8..0dbbae133b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ project(Bro C CXX) -cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR) +cmake_minimum_required(VERSION 2.6.3 FATAL_ERROR) include(cmake/CommonCMakeConfig.cmake) ######################################################################## @@ -16,17 +16,12 @@ endif () get_filename_component(BRO_SCRIPT_INSTALL_PATH ${BRO_SCRIPT_INSTALL_PATH} ABSOLUTE) -set(BRO_MAGIC_INSTALL_PATH ${BRO_ROOT_DIR}/share/bro/magic) -set(BRO_MAGIC_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/magic/database) - configure_file(bro-path-dev.in ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev.sh "export BROPATH=`${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev`\n" - "export BROMAGIC=\"${BRO_MAGIC_SOURCE_PATH}\"\n" "export PATH=\"${CMAKE_CURRENT_BINARY_DIR}/src\":$PATH\n") file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev.csh "setenv BROPATH `${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev`\n" - "setenv BROMAGIC \"${BRO_MAGIC_SOURCE_PATH}\"\n" "setenv PATH \"${CMAKE_CURRENT_BINARY_DIR}/src\":$PATH\n") file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" VERSION LIMIT_COUNT 1) @@ -39,32 +34,6 @@ set(VERSION_MAJ_MIN "${VERSION_MAJOR}.${VERSION_MINOR}") ######################################################################## ## Dependency Configuration -include(ExternalProject) - -# LOG_* options to ExternalProject_Add appear in CMake 2.8.3. If -# available, using them hides external project configure/build output. -if("${CMAKE_VERSION}" VERSION_GREATER 2.8.2) - set(EXTERNAL_PROJECT_LOG_OPTIONS - LOG_DOWNLOAD 1 LOG_UPDATE 1 LOG_CONFIGURE 1 LOG_BUILD 1 LOG_INSTALL 1) -else() - set(EXTERNAL_PROJECT_LOG_OPTIONS) -endif() - -set(LIBMAGIC_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libmagic-prefix) -set(LIBMAGIC_INCLUDE_DIR ${LIBMAGIC_PREFIX}/include) -set(LIBMAGIC_LIB_DIR ${LIBMAGIC_PREFIX}/lib) -set(LIBMAGIC_LIBRARY ${LIBMAGIC_LIB_DIR}/libmagic.a) -ExternalProject_Add(libmagic - PREFIX ${LIBMAGIC_PREFIX} - URL ${CMAKE_CURRENT_SOURCE_DIR}/src/3rdparty/file-5.17.tar.gz - CONFIGURE_COMMAND ./configure --enable-static --disable-shared - --prefix=${LIBMAGIC_PREFIX} - --includedir=${LIBMAGIC_INCLUDE_DIR} - --libdir=${LIBMAGIC_LIB_DIR} - BUILD_IN_SOURCE 1 - ${EXTERNAL_PROJECT_LOG_OPTIONS} -) - include(FindRequiredPackage) # Check cache value first to avoid displaying "Found sed" messages everytime @@ -103,7 +72,6 @@ include_directories(BEFORE ${OpenSSL_INCLUDE_DIR} ${BIND_INCLUDE_DIR} ${BinPAC_INCLUDE_DIR} - ${LIBMAGIC_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ) @@ -182,7 +150,6 @@ set(brodeps ${PCAP_LIBRARY} ${OpenSSL_LIBRARIES} ${BIND_LIBRARY} - ${LIBMAGIC_LIBRARY} ${ZLIB_LIBRARY} ${OPTLIBS} ) @@ -220,10 +187,6 @@ CheckOptionalBuildSources(aux/broctl Broctl INSTALL_BROCTL) CheckOptionalBuildSources(aux/bro-aux Bro-Aux INSTALL_AUX_TOOLS) CheckOptionalBuildSources(aux/broccoli Broccoli INSTALL_BROCCOLI) -install(DIRECTORY ./magic/database/ - DESTINATION ${BRO_MAGIC_INSTALL_PATH} -) - ######################################################################## ## Packaging Setup diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 9498556edc..414cf56b0c 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -14,8 +14,6 @@ if (NOT ${retval} EQUAL 0) message(FATAL_ERROR "Problem setting BROPATH") endif () -set(BROMAGIC ${BRO_MAGIC_SOURCE_PATH}) - # Configure the Sphinx config file (expand variables CMake might know about). configure_file(${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in ${CMAKE_CURRENT_BINARY_DIR}/conf.py @@ -34,7 +32,6 @@ add_custom_target(sphinxdoc ${CMAKE_CURRENT_SOURCE_DIR}/ ${SPHINX_INPUT_DIR} # Use Bro/Broxygen to dynamically generate reST for all Bro scripts. COMMAND BROPATH=${BROPATH} - BROMAGIC=${BROMAGIC} ${CMAKE_BINARY_DIR}/src/bro -X ${CMAKE_CURRENT_BINARY_DIR}/broxygen.conf broxygen >/dev/null diff --git a/doc/frameworks/signatures.rst b/doc/frameworks/signatures.rst index 884dcb8a47..1443f76ba1 100644 --- a/doc/frameworks/signatures.rst +++ b/doc/frameworks/signatures.rst @@ -64,8 +64,8 @@ expect that signature file in the same directory as the Bro script. The default extension of the file name is ``.sig``, and Bro appends that automatically when necessary. -Signature language -================== +Signature Language for Network Traffic +====================================== Let's look at the format of a signature more closely. Each individual signature has the format ``signature { }``. ```` @@ -286,6 +286,44 @@ two actions defined: connection (``"http"``, ``"ftp"``, etc.). This is used by Bro's dynamic protocol detection to activate analyzers on the fly. +Signature Language for File Content +=================================== + +The signature framework can also be used to identify MIME types of files +irrespective of the network protocol/connection over which the file is +transferred. A special type of signature can be written for this +purpose and will be used automatically by the :doc:`Files Framework +` or by Bro scripts that use the :bro:see:`file_magic` +built-in function. + +Conditions +---------- + +File signatures use a single type of content condition in the form of a +regular expression: + +``file-magic //`` + +This is analogous to the ``payload`` content condition for the network +traffic signature language described above. The difference is that +``payload`` signatures are applied to payloads of network connections, +but ``file-magic`` can be applied to any arbitrary data, it does not +have to be tied to a network protocol/connection. + +Actions +------- + +Upon matching a chunk of data, file signatures use the following action +to get information about that data's MIME type: + +``file-mime [, ]`` + +The arguments include the MIME type string associated with the file +magic regular expression and an optional "strength" as a signed integer. +Since multiple file magic signatures may match against a given chunk of +data, the strength value may be used to help choose a "winner". Higher +values are considered stronger. + Things to keep in mind when writing signatures ============================================== diff --git a/doc/install/install.rst b/doc/install/install.rst index 7400d640fe..058bb369eb 100644 --- a/doc/install/install.rst +++ b/doc/install/install.rst @@ -35,7 +35,7 @@ before you begin: To build Bro from source, the following additional dependencies are required: - * CMake 2.8.0 or greater (http://www.cmake.org) + * CMake 2.6.3 or greater (http://www.cmake.org) * Make * C/C++ compiler * SWIG (http://www.swig.org) diff --git a/magic b/magic deleted file mode 160000 index 99c6b89230..0000000000 --- a/magic +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 99c6b89230e2b9b0e781c42b0b9412d2ab4e14b2 diff --git a/scripts/base/frameworks/files/__load__.bro b/scripts/base/frameworks/files/__load__.bro index 783797e17b..2177d81e25 100644 --- a/scripts/base/frameworks/files/__load__.bro +++ b/scripts/base/frameworks/files/__load__.bro @@ -1 +1,2 @@ @load ./main.bro +@load ./magic diff --git a/scripts/base/frameworks/files/magic/__load__.bro b/scripts/base/frameworks/files/magic/__load__.bro new file mode 100644 index 0000000000..4a2de0926d --- /dev/null +++ b/scripts/base/frameworks/files/magic/__load__.bro @@ -0,0 +1,2 @@ +@load-sigs ./general +@load-sigs ./libmagic diff --git a/scripts/base/frameworks/files/magic/general.sig b/scripts/base/frameworks/files/magic/general.sig new file mode 100644 index 0000000000..595bcc2f62 --- /dev/null +++ b/scripts/base/frameworks/files/magic/general.sig @@ -0,0 +1,11 @@ +# General purpose file magic signatures. + +signature file-plaintext { + file-magic /([[:print:][:space:]]+)/ + file-mime "text/plain", -20 +} + +signature file-binary { + file-magic /(.*)([^[:print:][:space:]]+)/ + file-mime "binary", -10 +} diff --git a/scripts/base/frameworks/files/magic/libmagic.sig b/scripts/base/frameworks/files/magic/libmagic.sig new file mode 100644 index 0000000000..25f5ba8c0f --- /dev/null +++ b/scripts/base/frameworks/files/magic/libmagic.sig @@ -0,0 +1,4199 @@ +# These signatures were semi-automatically generated from libmagic's +# (~ v5.17) magic database rules that have an associated mime type. +# After generating, they were all manually reviewed and occassionally +# needed minor modifications by hand or just ommited depending on +# the complexity of the original magic rules. +# +# The instrumented version of the `file` command used to generate these +# is located at: https://github.com/jsiwek/file/tree/bro-signatures. + +# >2080 string,=Foglio di lavoro Microsoft Exce (len=31), ["%s"], swap_endian=0 +signature file-magic-auto0 { + file-mime "application/vnd.ms-excel", 340 + file-magic /(.{2080})(Foglio di lavoro Microsoft Exce)/ +} + +# >2 string,=---BEGIN PGP PUBLIC KEY BLOCK- (len=30), ["PGP public key block"], swap_endian=0 +signature file-magic-auto1 { + file-mime "application/pgp-keys", 330 + file-magic /(.{2})(\x2d\x2d\x2dBEGIN PGP PUBLIC KEY BLOCK\x2d)/ +} + +# >2080 string,=Microsoft Excel 5.0 Worksheet (len=29), ["%s"], swap_endian=0 +signature file-magic-auto2 { + file-mime "application/vnd.ms-excel", 320 + file-magic /(.{2080})(Microsoft Excel 5\x2e0 Worksheet)/ +} + +# >11 string,=must be converted with BinHex (len=29), ["BinHex binary text"], swap_endian=0 +signature file-magic-auto3 { + file-mime "application/mac-binhex40", 320 + file-magic /(.{11})(must be converted with BinHex)/ +} + +# >2080 string,=Microsoft Word 6.0 Document (len=27), ["%s"], swap_endian=0 +signature file-magic-auto4 { + file-mime "application/msword", 300 + file-magic /(.{2080})(Microsoft Word 6\x2e0 Document)/ +} + +# >2080 string,=Documento Microsoft Word 6 (len=26), ["Spanish Microsoft Word 6 document data"], swap_endian=0 +signature file-magic-auto5 { + file-mime "application/msword", 290 + file-magic /(.{2080})(Documento Microsoft Word 6)/ +} + +# >0 string,=-----BEGIN PGP SIGNATURE- (len=25), ["PGP signature"], swap_endian=0 +signature file-magic-auto6 { + file-mime "application/pgp-signature", 280 + file-magic /(\x2d\x2d\x2d\x2d\x2dBEGIN PGP SIGNATURE\x2d)/ +} + +# >10 string,=# This is a shell archive (len=25), ["shell archive text"], swap_endian=0 +signature file-magic-auto7 { + file-mime "application/octet-stream", 280 + file-magic /(.{10})(\x23 This is a shell archive)/ +} + +# >0 string,=-----BEGIN PGP MESSAGE- (len=23), ["PGP message"], swap_endian=0 +signature file-magic-auto8 { + file-mime "application/pgp", 260 + file-magic /(\x2d\x2d\x2d\x2d\x2dBEGIN PGP MESSAGE\x2d)/ +} + +# >0 string,=0 string,=>24 regex,=[0-9.]+ (len=7), [", version %s"], swap_endian=0 +signature file-magic-auto10 { + file-mime "text/x-php", 37 + file-magic /(\x3c\x3fphp \x2f\x2a Smarty version)(.{1})([0-9.]+)/ +} + +# >0 string/w,=0 string/wt,=#! /usr/local/bin/nawk (len=22), ["new awk script text executable"], swap_endian=0 +signature file-magic-auto12 { + file-mime "text/x-nawk", 250 + file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fnawk)/ +} + +# >0 string/wt,=#! /usr/local/bin/gawk (len=22), ["GNU awk script text executable"], swap_endian=0 +signature file-magic-auto13 { + file-mime "text/x-gawk", 250 + file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fgawk)/ +} + +# >0 string/wt,=#! /usr/local/bin/bash (len=22), ["Bourne-Again shell script text executable"], swap_endian=0 +signature file-magic-auto14 { + file-mime "text/x-shellscript", 250 + file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fbash)/ +} + +# >0 string/wt,=#! /usr/local/bin/tcsh (len=22), ["Tenex C shell script text executable"], swap_endian=0 +signature file-magic-auto15 { + file-mime "text/x-shellscript", 250 + file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2ftcsh)/ +} + +# >0 string/wt,=#! /usr/local/bin/zsh (len=21), ["Paul Falstad's zsh script text executable"], swap_endian=0 +signature file-magic-auto16 { + file-mime "text/x-shellscript", 240 + file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fzsh)/ +} + +# >0 string/wt,=#! /usr/local/bin/ash (len=21), ["Neil Brown's ash script text executable"], swap_endian=0 +signature file-magic-auto17 { + file-mime "text/x-shellscript", 240 + file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fash)/ +} + +# >0 string/wt,=#! /usr/local/bin/ae (len=20), ["Neil Brown's ae script text executable"], swap_endian=0 +signature file-magic-auto18 { + file-mime "text/x-shellscript", 230 + file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fae)/ +} + +# >0 string,=# PaCkAgE DaTaStReAm (len=20), ["pkg Datastream (SVR4)"], swap_endian=0 +signature file-magic-auto19 { + file-mime "application/x-svr4-package", 230 + file-magic /(\x23 PaCkAgE DaTaStReAm)/ +} + +# >0 string,=Creative Voice File (len=19), ["Creative Labs voice data"], swap_endian=0 +signature file-magic-auto20 { + file-mime "audio/x-unknown", 220 + file-magic /(Creative Voice File)/ +} + +# >0 string/t,=[KDE Desktop Entry] (len=19), ["KDE desktop entry"], swap_endian=0 +signature file-magic-auto21 { + file-mime "application/x-kdelnk", 220 + file-magic /(\x5bKDE Desktop Entry\x5d)/ +} + +# >512 string,=R\000o\000o\000t\000 \000E\000n\000t\000r\000y (len=19), ["Microsoft Word Document"], swap_endian=0 +signature file-magic-auto22 { + file-mime "application/msword", 220 + file-magic /(.{512})(R\x00o\x00o\x00t\x00 \x00E\x00n\x00t\x00r\x00y)/ +} + +# >0 string,=!\n__________E (len=19), ["MIPS archive"], swap_endian=0 +signature file-magic-auto23 { + file-mime "application/x-archive", 220 + file-magic /(\x21\x3carch\x3e\x0a\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x5fE)/ +} + +# >0 string/wt,=#! /usr/local/tcsh (len=18), ["Tenex C shell script text executable"], swap_endian=0 +signature file-magic-auto24 { + file-mime "text/x-shellscript", 210 + file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2ftcsh)/ +} + +# >0 string/wt,=#! /usr/local/bash (len=18), ["Bourne-Again shell script text executable"], swap_endian=0 +signature file-magic-auto25 { + file-mime "text/x-shellscript", 210 + file-magic /(\x23\x21 ?\x2fusr\x2flocal\x2fbash)/ +} + +# >0 string/t,=# KDE Config File (len=17), ["KDE config file"], swap_endian=0 +signature file-magic-auto26 { + file-mime "application/x-kdelnk", 200 + file-magic /(\x23 KDE Config File)/ +} + +# >0 string,=RF64\377\377\377\377WAVEds64 (len=16), ["MBWF/RF64 audio"], swap_endian=0 +signature file-magic-auto27 { + file-mime "audio/x-wav", 190 + file-magic /(RF64\xff\xff\xff\xffWAVEds64)/ +} + +# >0 string,=riff.\221\317\021\245\326(\333\004\301\000\000 (len=16), ["Sony Wave64 RIFF data"], swap_endian=0 +# >>24 string,=wave\363\254\323\021\214\321\000\300O\216\333\212 (len=16), [", WAVE 64 audio"], swap_endian=0 +signature file-magic-auto28 { + file-mime "audio/x-w64", 190 + file-magic /(riff\x2e\x91\xcf\x11\xa5\xd6\x28\xdb\x04\xc1\x00\x00)(.{8})(wave\xf3\xac\xd3\x11\x8c\xd1\x00\xc0O\x8e\xdb\x8a)/ +} + +# >0 string/wt,=#! /usr/bin/nawk (len=16), ["new awk script text executable"], swap_endian=0 +signature file-magic-auto29 { + file-mime "text/x-nawk", 190 + file-magic /(\x23\x21 ?\x2fusr\x2fbin\x2fnawk)/ +} + +# >0 string/wt,=#! /usr/bin/tcsh (len=16), ["Tenex C shell script text executable"], swap_endian=0 +signature file-magic-auto30 { + file-mime "text/x-shellscript", 190 + file-magic /(\x23\x21 ?\x2fusr\x2fbin\x2ftcsh)/ +} + +# >0 string/wt,=#! /usr/bin/gawk (len=16), ["GNU awk script text executable"], swap_endian=0 +signature file-magic-auto31 { + file-mime "text/x-gawk", 190 + file-magic /(\x23\x21 ?\x2fusr\x2fbin\x2fgawk)/ +} + +# >369 string,=MICROSOFT PIFEX\000 (len=16), ["Windows Program Information File"], swap_endian=0 +signature file-magic-auto32 { + file-mime "application/x-dosexec", 190 + file-magic /(.{369})(MICROSOFT PIFEX\x00)/ +} + +# >0 string/wt,=#! /usr/bin/bash (len=16), ["Bourne-Again shell script text executable"], swap_endian=0 +signature file-magic-auto33 { + file-mime "text/x-shellscript", 190 + file-magic /(\x23\x21 ?\x2fusr\x2fbin\x2fbash)/ +} + +# >0 string/w,=#VRML V1.0 ascii (len=16), ["VRML 1 file"], swap_endian=0 +signature file-magic-auto34 { + file-mime "model/vrml", 190 + file-magic /(\x23VRML ?V1\x2e0 ?ascii)/ +} + +# >0 string,=0 string,=Extended Module: (len=16), ["Fasttracker II module sound data"], swap_endian=0 +signature file-magic-auto36 { + file-mime "audio/x-mod", 190 + file-magic /(Extended Module\x3a)/ +} + +# >0 string/t,=0 string/t,=0 string,=0 string/t,=>20 search/wc/1000,=0 string/t,=>15 string,>\000 (len=1), [""], swap_endian=0 +# >>>19 search/Wctb/4096,=0 string/t,=>15 string,>\000 (len=1), [""], swap_endian=0 +# >>>19 search/Wctb/4096,=0 string/t,=>15 string,>\000 (len=1), [""], swap_endian=0 +# >>>19 search/4096,=0 string,=>15 string,>\000 (len=1), [""], swap_endian=0 +# >>>19 search/4096,=0 string,=>15 string,>\000 (len=1), [""], swap_endian=0 +# >>>19 search/4096,=0 string/t,=>15 string,>\000 (len=1), [""], swap_endian=0 +# >>>19 search/Wctb/4096,=0 string/c,=BEGIN:VCALENDAR (len=15), ["vCalendar calendar file"], swap_endian=0 +signature file-magic-auto47 { + file-mime "text/calendar", 180 + file-magic /(BEGIN\x3aVCALENDAR)/ +} + +# >4 string,=Standard Jet DB (len=15), ["Microsoft Access Database"], swap_endian=0 +signature file-magic-auto48 { + file-mime "application/x-msaccess", 180 + file-magic /(.{4})(Standard Jet DB)/ +} + +# >4 string,=Standard ACE DB (len=15), ["Microsoft Access Database"], swap_endian=0 +signature file-magic-auto49 { + file-mime "application/x-msaccess", 180 + file-magic /(.{4})(Standard ACE DB)/ +} + +# >0 string/w,=#VRML V2.0 utf8 (len=15), ["ISO/IEC 14772 VRML 97 file"], swap_endian=0 +signature file-magic-auto50 { + file-mime "model/vrml", 180 + file-magic /(\x23VRML ?V2\x2e0 ?utf8)/ +} + +# >0 string/wt,=#! /usr/bin/awk (len=15), ["awk script text executable"], swap_endian=0 +signature file-magic-auto51 { + file-mime "text/x-awk", 180 + file-magic /(\x23\x21 ?\x2fusr\x2fbin\x2fawk)/ +} + +# >0 string/wt,=#! /usr/bin/zsh (len=15), ["Paul Falstad's zsh script text executable"], swap_endian=0 +signature file-magic-auto52 { + file-mime "text/x-shellscript", 180 + file-magic /(\x23\x21 ?\x2fusr\x2fbin\x2fzsh)/ +} + +# >0 string,=MAS_UTrack_V00 (len=14), [""], swap_endian=0 +# >>14 string,>/0 (len=2), ["ultratracker V1.%.1s module sound data"], swap_endian=0 +signature file-magic-auto53 { + file-mime "audio/x-mod", 20 + file-magic /(MAS\x5fUTrack\x5fV00)(\x2f0)/ +} + +# >0 string,=!\ndebian (len=14), [""], swap_endian=0 +signature file-magic-auto54 { + file-mime "application/x-debian-package", 171 + file-magic /(\x21\x3carch\x3e\x0adebian)/ +} + +# >0 string,=II\032\000\000\000HEAPCCDR (len=14), ["Canon CIFF raw image data"], swap_endian=0 +signature file-magic-auto55 { + file-mime "image/x-canon-crw", 170 + file-magic /(II\x1a\x00\x00\x00HEAPCCDR)/ +} + +# >0 string/t,=Relay-Version: (len=14), ["old news text"], swap_endian=0 +signature file-magic-auto56 { + file-mime "message/rfc822", 170 + file-magic /(Relay\x2dVersion\x3a)/ +} + +# >0 string,=ToKyO CaBiNeT\n (len=14), ["Tokyo Cabinet"], swap_endian=0 +# >>32 byte&,=0x00, [", Hash"], swap_endian=0 +signature file-magic-auto57 { + file-mime "application/x-tokyocabinet-hash", 40 + file-magic /(ToKyO CaBiNeT\x0a)(.{18})([\x00])/ +} + +# >0 string,=ToKyO CaBiNeT\n (len=14), ["Tokyo Cabinet"], swap_endian=0 +# >>32 byte&,=0x01, [", B+ tree"], swap_endian=0 +signature file-magic-auto58 { + file-mime "application/x-tokyocabinet-btree", 40 + file-magic /(ToKyO CaBiNeT\x0a)(.{18})([\x01])/ +} + +# >0 string,=ToKyO CaBiNeT\n (len=14), ["Tokyo Cabinet"], swap_endian=0 +# >>32 byte&,=0x02, [", Fixed-length"], swap_endian=0 +signature file-magic-auto59 { + file-mime "application/x-tokyocabinet-fixed", 40 + file-magic /(ToKyO CaBiNeT\x0a)(.{18})([\x02])/ +} + +# >0 string,=ToKyO CaBiNeT\n (len=14), ["Tokyo Cabinet"], swap_endian=0 +# >>32 byte&,=0x03, [", Table"], swap_endian=0 +signature file-magic-auto60 { + file-mime "application/x-tokyocabinet-table", 40 + file-magic /(ToKyO CaBiNeT\x0a)(.{18})([\x03])/ +} + +# >39 string,=0 string/t,=[BitmapInfo2] (len=13), ["Polar Monitor Bitmap text"], swap_endian=0 +signature file-magic-auto62 { + file-mime "image/x-polar-monitor-bitmap", 160 + file-magic /(\x5bBitmapInfo2\x5d)/ +} + +# >0 string,=SplineFontDB: (len=13), ["Spline Font Database "], swap_endian=0 +signature file-magic-auto63 { + file-mime "application/vnd.font-fontforge-sfd", 160 + file-magic /(SplineFontDB\x3a)/ +} + +# >0 string/ct,=delivered-to: (len=13), ["SMTP mail text"], swap_endian=0 +signature file-magic-auto64 { + file-mime "message/rfc822", 160 + file-magic /([dD][eE][lL][iI][vV][eE][rR][eE][dD]\x2d[tT][oO]\x3a)/ +} + +# >0 string/ct,=return-path: (len=12), ["SMTP mail text"], swap_endian=0 +signature file-magic-auto65 { + file-mime "message/rfc822", 150 + file-magic /([rR][eE][tT][uU][rR][nN]\x2d[pP][aA][tT][hH]\x3a)/ +} + +# >0 string,=\000\000\000\fjP \r\n\207\n (len=12), ["JPEG 2000"], swap_endian=0 +# >>20 string,=jp2 (len=4), ["Part 1 (JP2)"], swap_endian=0 +signature file-magic-auto66 { + file-mime "image/jp2", 70 + file-magic /(\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a)(.{8})(jp2 )/ +} + +# >0 string,=\000\000\000\fjP \r\n\207\n (len=12), ["JPEG 2000"], swap_endian=0 +# >>20 string,=jpx (len=4), ["Part 2 (JPX)"], swap_endian=0 +signature file-magic-auto67 { + file-mime "image/jpx", 70 + file-magic /(\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a)(.{8})(jpx )/ +} + +# >0 string,=\000\000\000\fjP \r\n\207\n (len=12), ["JPEG 2000"], swap_endian=0 +# >>20 string,=jpm (len=4), ["Part 6 (JPM)"], swap_endian=0 +signature file-magic-auto68 { + file-mime "image/jpm", 70 + file-magic /(\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a)(.{8})(jpm )/ +} + +# >0 string,=\000\000\000\fjP \r\n\207\n (len=12), ["JPEG 2000"], swap_endian=0 +# >>20 string,=mjp2 (len=4), ["Part 3 (MJ2)"], swap_endian=0 +signature file-magic-auto69 { + file-mime "video/mj2", 70 + file-magic /(\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a)(.{8})(mjp2)/ +} + +# >0 string/w,=0 string/wt,=#! /bin/tcsh (len=12), ["Tenex C shell script text executable"], swap_endian=0 +signature file-magic-auto71 { + file-mime "text/x-shellscript", 150 + file-magic /(\x23\x21 ?\x2fbin\x2ftcsh)/ +} + +# >0 string/wt,=#! /bin/nawk (len=12), ["new awk script text executable"], swap_endian=0 +signature file-magic-auto72 { + file-mime "text/x-nawk", 150 + file-magic /(\x23\x21 ?\x2fbin\x2fnawk)/ +} + +# >0 string/wt,=#! /bin/gawk (len=12), ["GNU awk script text executable"], swap_endian=0 +signature file-magic-auto73 { + file-mime "text/x-gawk", 150 + file-magic /(\x23\x21 ?\x2fbin\x2fgawk)/ +} + +# >0 string/wt,=#! /bin/bash (len=12), ["Bourne-Again shell script text executable"], swap_endian=0 +signature file-magic-auto74 { + file-mime "text/x-shellscript", 150 + file-magic /(\x23\x21 ?\x2fbin\x2fbash)/ +} + +# >0 string/wt,=#! /bin/awk (len=11), ["awk script text executable"], swap_endian=0 +signature file-magic-auto75 { + file-mime "text/x-awk", 140 + file-magic /(\x23\x21 ?\x2fbin\x2fawk)/ +} + +# >0 string,=filedesc:// (len=11), ["Internet Archive File"], swap_endian=0 +signature file-magic-auto76 { + file-mime "application/x-ia-arc", 140 + file-magic /(filedesc\x3a\x2f\x2f)/ +} + +# >38 string,=Spreadsheet (len=11), ["sc spreadsheet file"], swap_endian=0 +signature file-magic-auto77 { + file-mime "application/x-sc", 140 + file-magic /(.{38})(Spreadsheet)/ +} + +# >0 string,=d8:announce (len=11), ["BitTorrent file"], swap_endian=0 +signature file-magic-auto78 { + file-mime "application/x-bittorrent", 140 + file-magic /(d8\x3aannounce)/ +} + +# >0 string/wt,=#! /bin/csh (len=11), ["C shell script text executable"], swap_endian=0 +signature file-magic-auto79 { + file-mime "text/x-shellscript", 140 + file-magic /(\x23\x21 ?\x2fbin\x2fcsh)/ +} + +# >0 string/wt,=#! /bin/ksh (len=11), ["Korn shell script text executable"], swap_endian=0 +signature file-magic-auto80 { + file-mime "text/x-shellscript", 140 + file-magic /(\x23\x21 ?\x2fbin\x2fksh)/ +} + +# >0 string/wt,=#! /bin/zsh (len=11), ["Paul Falstad's zsh script text executable"], swap_endian=0 +signature file-magic-auto81 { + file-mime "text/x-shellscript", 140 + file-magic /(\x23\x21 ?\x2fbin\x2fzsh)/ +} + +# >0 string/c,=BEGIN:VCARD (len=11), ["vCard visiting card"], swap_endian=0 +signature file-magic-auto82 { + file-mime "text/x-vcard", 140 + file-magic /(BEGIN\x3aVCARD)/ +} + +# >0 string,=HEADER (len=10), [""], swap_endian=0 +# >>&0 regex/1,=^.{40} (len=6), [""], swap_endian=0 +# >>>&0 regex/1,=[0-9]{2}-[A-Z]{3}-[0-9]{2} {3} (len=30), [""], swap_endian=0 +# >>>>&0 regex/s/1,=[A-Z0-9]{4}.{14}$ (len=17), [""], swap_endian=0 +# >>>>>&0 regex/1,=[A-Z0-9]{4} (len=11), ["Protein Data Bank data, ID Code %s"], swap_endian=0 +signature file-magic-auto83 { + file-mime "chemical/x-pdb", 41 + file-magic /(HEADER )(^.{40})([0-9]{2}-[A-Z]{3}-[0-9]{2} {3})([A-Z0-9]{4}.{14}$)([A-Z0-9]{4})/ +} + +# >0 string/t,=Forward to (len=10), ["mail forwarding text"], swap_endian=0 +signature file-magic-auto84 { + file-mime "message/rfc822", 130 + file-magic /(Forward to)/ +} + +# >0 string/wt,=#! /bin/sh (len=10), ["POSIX shell script text executable"], swap_endian=0 +signature file-magic-auto85 { + file-mime "text/x-shellscript", 130 + file-magic /(\x23\x21 ?\x2fbin\x2fsh)/ +} + +# >0 string,=II*\000\020\000\000\000CR (len=10), ["Canon CR2 raw image data"], swap_endian=0 +signature file-magic-auto86 { + file-mime "image/x-canon-cr2", 130 + file-magic /(II\x2a\x00\x10\x00\x00\x00CR)/ +} + +# >0 string,=0 search/4096,=--- (len=4), [""], swap_endian=0 +# >>&0 search/1024,=\n (len=1), [""], swap_endian=0 +# >>>&0 search/1,=+++ (len=4), [""], swap_endian=0 +# >>>>&0 search/1024,=\n (len=1), [""], swap_endian=0 +# >>>>>&0 search/1,=@@ (len=2), ["unified diff output text"], swap_endian=0 +signature file-magic-auto88 { + file-mime "text/x-diff", 40 + file-magic /(.*)(\x2d\x2d\x2d )(.*)(\x0a)(.*)(\x2b\x2b\x2b )(.*)(\x0a)(.*)(\x40\x40)/ +} + +# >0 string/t,=Received: (len=9), ["RFC 822 mail text"], swap_endian=0 +signature file-magic-auto89 { + file-mime "message/rfc822", 120 + file-magic /(Received\x3a)/ +} + +# >0 string,=2112 string,=MSWordDoc (len=9), ["Microsoft Word document data"], swap_endian=0 +signature file-magic-auto91 { + file-mime "application/msword", 120 + file-magic /(.{2112})(MSWordDoc)/ +} + +# >0 string/t,=N#! rnews (len=9), ["mailed, batched news text"], swap_endian=0 +signature file-magic-auto92 { + file-mime "message/rfc822", 120 + file-magic /(N\x23\x21 rnews)/ +} + +# >0 string/b,=WordPro\r\373 (len=9), ["Lotus WordPro"], swap_endian=0 +signature file-magic-auto93 { + file-mime "application/vnd.lotus-wordpro", 120 + file-magic /(WordPro\x0d\xfb)/ +} + +# >0 string,=LPKSHHRH (len=8), [""], swap_endian=0 +# >>16 ubyte&000000fc,=0x00, [""], swap_endian=0 +# >>>24 ubequad&,>0 (0x0000000000000000), [""], swap_endian=0 +# >>>>32 ubequad&,>0 (0x0000000000000000), [""], swap_endian=0 +# >>>>>40 ubequad&,>0 (0x0000000000000000), [""], swap_endian=0 +# >>>>>>48 ubequad&,>0 (0x0000000000000000), [""], swap_endian=0 +# >>>>>>>56 ubequad&,>0 (0x0000000000000000), [""], swap_endian=0 +# >>>>>>>>64 ubequad&,>0 (0x0000000000000000), ["Journal file"], swap_endian=0 +signature file-magic-auto94 { + file-mime "application/octet-stream", 80 + file-magic /(LPKSHHRH)(.{8})([\x00\x01\x02\x03])(.{7})([^\x00]{8})([^\x00]{8})([^\x00]{8})([^\x00]{8})([^\x00]{8})([^\x00]{8})/ +} + +# >0 string,=AT&TFORM (len=8), [""], swap_endian=0 +# >>12 string,=DJVM (len=4), ["DjVu multiple page document"], swap_endian=0 +signature file-magic-auto95 { + file-mime "image/vnd.djvu", 70 + file-magic /(AT\x26TFORM)(.{4})(DJVM)/ +} + +# >0 string,=AT&TFORM (len=8), [""], swap_endian=0 +# >>12 string,=DJVU (len=4), ["DjVu image or single page document"], swap_endian=0 +signature file-magic-auto96 { + file-mime "image/vnd.djvu", 70 + file-magic /(AT\x26TFORM)(.{4})(DJVU)/ +} + +# >0 string,=AT&TFORM (len=8), [""], swap_endian=0 +# >>12 string,=DJVI (len=4), ["DjVu shared document"], swap_endian=0 +signature file-magic-auto97 { + file-mime "image/vnd.djvu", 70 + file-magic /(AT\x26TFORM)(.{4})(DJVI)/ +} + +# >0 string,=AT&TFORM (len=8), [""], swap_endian=0 +# >>12 string,=THUM (len=4), ["DjVu page thumbnails"], swap_endian=0 +signature file-magic-auto98 { + file-mime "image/vnd.djvu", 70 + file-magic /(AT\x26TFORM)(.{4})(THUM)/ +} + +# >0 string/t,=#! rnews (len=8), ["batched news text"], swap_endian=0 +signature file-magic-auto99 { + file-mime "message/rfc822", 110 + file-magic /(\x23\x21 rnews)/ +} + +# >0 string/b,=MSCF\000\000\000\000 (len=8), ["Microsoft Cabinet archive data"], swap_endian=0 +signature file-magic-auto100 { + file-mime "application/vnd.ms-cab-compressed", 110 + file-magic /(MSCF\x00\x00\x00\x00)/ +} + +# >0 string/b,=\320\317\021\340\241\261\032\341 (len=8), ["Microsoft Office Document"], swap_endian=0 +signature file-magic-auto101 { + file-mime "application/msword", 110 + file-magic /(\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1)/ +} + +# >21 string/c,=!SCREAM! (len=8), ["Screamtracker 2 module sound data"], swap_endian=0 +signature file-magic-auto102 { + file-mime "audio/x-mod", 110 + file-magic /(.{21})(\x21SCREAM\x21)/ +} + +# >21 string,=BMOD2STM (len=8), ["Screamtracker 2 module sound data"], swap_endian=0 +signature file-magic-auto103 { + file-mime "audio/x-mod", 110 + file-magic /(.{21})(BMOD2STM)/ +} + +# >0 string/b,=ITOLITLS (len=8), ["Microsoft Reader eBook Data"], swap_endian=0 +# >>8 lelong&,x, [", version %u"], swap_endian=0 +signature file-magic-auto104 { + file-mime "application/x-ms-reader", 1 + file-magic /(ITOLITLS)(.{4})/ +} + +# >4096 string,=\211HDF\r\n\032\n (len=8), ["Hierarchical Data Format (version 5) with 4k user block"], swap_endian=0 +signature file-magic-auto105 { + file-mime "application/x-hdf", 110 + file-magic /(.{4096})(\x89HDF\x0d\x0a\x1a\x0a)/ +} + +# >2048 string,=\211HDF\r\n\032\n (len=8), ["Hierarchical Data Format (version 5) with 2k user block"], swap_endian=0 +signature file-magic-auto106 { + file-mime "application/x-hdf", 110 + file-magic /(.{2048})(\x89HDF\x0d\x0a\x1a\x0a)/ +} + +# >1024 string,=\211HDF\r\n\032\n (len=8), ["Hierarchical Data Format (version 5) with 1k user block"], swap_endian=0 +signature file-magic-auto107 { + file-mime "application/x-hdf", 110 + file-magic /(.{1024})(\x89HDF\x0d\x0a\x1a\x0a)/ +} + +# >512 string,=\211HDF\r\n\032\n (len=8), ["Hierarchical Data Format (version 5) with 512 bytes user block"], swap_endian=0 +signature file-magic-auto108 { + file-mime "application/x-hdf", 110 + file-magic /(.{512})(\x89HDF\x0d\x0a\x1a\x0a)/ +} + +# >0 string,=\211HDF\r\n\032\n (len=8), ["Hierarchical Data Format (version 5) data"], swap_endian=0 +signature file-magic-auto109 { + file-mime "application/x-hdf", 110 + file-magic /(\x89HDF\x0d\x0a\x1a\x0a)/ +} + +# >0 string,=\211PNG\r\n\032\n (len=8), ["PNG image data"], swap_endian=0 +signature file-magic-auto110 { + file-mime "image/png", 110 + file-magic /(\x89PNG\x0d\x0a\x1a\x0a)/ +} + +# >36 string,=acspSUNW (len=8), ["Sun KCMS ICC Profile"], swap_endian=0 +signature file-magic-auto111 { + file-mime "application/vnd.iccprofile", 110 + file-magic /(.{36})(acspSUNW)/ +} + +# >36 string,=acspSGI (len=8), ["SGI ICC Profile"], swap_endian=0 +signature file-magic-auto112 { + file-mime "application/vnd.iccprofile", 110 + file-magic /(.{36})(acspSGI )/ +} + +# >36 string,=acspMSFT (len=8), ["Microsoft ICM Color Profile"], swap_endian=0 +signature file-magic-auto113 { + file-mime "application/vnd.iccprofile", 110 + file-magic /(.{36})(acspMSFT)/ +} + +# >36 string,=acspAPPL (len=8), ["ColorSync ICC Profile"], swap_endian=0 +signature file-magic-auto114 { + file-mime "application/vnd.iccprofile", 110 + file-magic /(.{36})(acspAPPL)/ +} + +# >0 string,=gimp xcf (len=8), ["GIMP XCF image data,"], swap_endian=0 +signature file-magic-auto115 { + file-mime "image/x-xcf", 110 + file-magic /(gimp xcf)/ +} + +# >512 string,=R\000o\000o\000t\000 (len=8), ["Hangul (Korean) Word Processor File 2000"], swap_endian=0 +signature file-magic-auto116 { + file-mime "application/x-hwp", 110 + file-magic /(.{512})(R\x00o\x00o\x00t\x00)/ +} + +# >257 string,=ustar \000 (len=8), ["GNU tar archive"], swap_endian=0 +signature file-magic-auto117 { + file-mime "application/x-tar", 110 + file-magic /(.{257})(ustar \x00)/ +} + +# >0 string,=0 string,=PK\a\bPK\003\004 (len=8), ["Zip multi-volume archive data, at least PKZIP v2.50 to extract"], swap_endian=0 +signature file-magic-auto119 { + file-mime "application/zip", 110 + file-magic /(PK\x07\x08PK\x03\x04)/ +} + +# >0 string/b,=\t\004\006\000\000\000\020\000 (len=8), ["Microsoft Excel Worksheet"], swap_endian=0 +signature file-magic-auto120 { + file-mime "application/vnd.ms-excel", 110 + file-magic /(\x09\x04\x06\x00\x00\x00\x10\x00)/ +} + +# >0 string/b,=WordPro\000 (len=8), ["Lotus WordPro"], swap_endian=0 +signature file-magic-auto121 { + file-mime "application/vnd.lotus-wordpro", 110 + file-magic /(WordPro\x00)/ +} + +# >0 string/t,=Article (len=7), ["saved news text"], swap_endian=0 +signature file-magic-auto122 { + file-mime "message/news", 100 + file-magic /(Article)/ +} + +# >0 string,=\037\213 (len=2), ["gzip compressed data"], swap_endian=0 +signature file-magic-auto123 { + file-mime "application/x-gzip", 100 + file-magic /(\x1f\x8b)/ +} + +# >0 string/t,=Pipe to (len=7), ["mail piping text"], swap_endian=0 +signature file-magic-auto124 { + file-mime "message/rfc822", 100 + file-magic /(Pipe to)/ +} + +# >0 string,=.RMF\000\000\000 (len=7), ["RealMedia file"], swap_endian=0 +signature file-magic-auto125 { + file-mime "application/vnd.rn-realmedia", 100 + file-magic /(\x2eRMF\x00\x00\x00)/ +} + +# >0 string,=StuffIt (len=7), ["StuffIt Archive"], swap_endian=0 +signature file-magic-auto126 { + file-mime "application/x-stuffit", 100 + file-magic /(StuffIt)/ +} + +# >0 string,=! (len=7), ["current ar archive"], swap_endian=0 +signature file-magic-auto127 { + file-mime "application/x-archive", 100 + file-magic /(\x21\x3carch\x3e)/ +} + +# >0 string,=P5 (len=2), [""], swap_endian=0 +# >>3 regex,=[0-9]{1,50} (len=12), [", size = %sx"], swap_endian=0 +# >>>3 regex,= [0-9]{1,50} (len=12), ["%s"], swap_endian=0 +signature file-magic-auto128 { + file-mime "image/x-portable-greymap", 42 + file-magic /(P5)(.{1})([0-9]{1,50} )( [0-9]{1,50})/ +} + +# >0 string,=P6 (len=2), [""], swap_endian=0 +# >>3 regex,=[0-9]{1,50} (len=12), [", size = %sx"], swap_endian=0 +# >>>3 regex,= [0-9]{1,50} (len=12), ["%s"], swap_endian=0 +signature file-magic-auto129 { + file-mime "image/x-portable-pixmap", 42 + file-magic /(P6)(.{1})([0-9]{1,50} )( [0-9]{1,50})/ +} + +# >0 string,=P4 (len=2), [""], swap_endian=0 +# >>3 regex,=[0-9]{1,50} (len=12), [", size = %sx"], swap_endian=0 +# >>>3 regex,= [0-9]{1,50} (len=12), ["%s"], swap_endian=0 +signature file-magic-auto130 { + file-mime "image/x-portable-bitmap", 42 + file-magic /(P4)(.{1})([0-9]{1,50} )( [0-9]{1,50})/ +} + +# >257 string,=ustar\000 (len=6), ["POSIX tar archive"], swap_endian=0 +signature file-magic-auto131 { + file-mime "application/x-tar", 90 + file-magic /(.{257})(ustar\x00)/ +} + +# >0 string,=AC1.40 (len=6), ["DWG AutoDesk AutoCAD Release 1.40"], swap_endian=0 +signature file-magic-auto132 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1\x2e40)/ +} + +# >0 string,=AC1.50 (len=6), ["DWG AutoDesk AutoCAD Release 2.05"], swap_endian=0 +signature file-magic-auto133 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1\x2e50)/ +} + +# >0 string,=AC2.10 (len=6), ["DWG AutoDesk AutoCAD Release 2.10"], swap_endian=0 +signature file-magic-auto134 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC2\x2e10)/ +} + +# >0 string,=AC2.21 (len=6), ["DWG AutoDesk AutoCAD Release 2.21"], swap_endian=0 +signature file-magic-auto135 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC2\x2e21)/ +} + +# >0 string,=AC2.22 (len=6), ["DWG AutoDesk AutoCAD Release 2.22"], swap_endian=0 +signature file-magic-auto136 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC2\x2e22)/ +} + +# >0 string,=AC1001 (len=6), ["DWG AutoDesk AutoCAD Release 2.22"], swap_endian=0 +signature file-magic-auto137 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1001)/ +} + +# >0 string,=AC1002 (len=6), ["DWG AutoDesk AutoCAD Release 2.50"], swap_endian=0 +signature file-magic-auto138 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1002)/ +} + +# >0 string,=AC1003 (len=6), ["DWG AutoDesk AutoCAD Release 2.60"], swap_endian=0 +signature file-magic-auto139 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1003)/ +} + +# >0 string,=AC1004 (len=6), ["DWG AutoDesk AutoCAD Release 9"], swap_endian=0 +signature file-magic-auto140 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1004)/ +} + +# >0 string,=AC1006 (len=6), ["DWG AutoDesk AutoCAD Release 10"], swap_endian=0 +signature file-magic-auto141 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1006)/ +} + +# >0 string,=AC1009 (len=6), ["DWG AutoDesk AutoCAD Release 11/12"], swap_endian=0 +signature file-magic-auto142 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1009)/ +} + +# >0 string,=AC1012 (len=6), ["DWG AutoDesk AutoCAD Release 13"], swap_endian=0 +signature file-magic-auto143 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1012)/ +} + +# >0 string,=AC1014 (len=6), ["DWG AutoDesk AutoCAD Release 14"], swap_endian=0 +signature file-magic-auto144 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1014)/ +} + +# >0 string,=AC1015 (len=6), ["DWG AutoDesk AutoCAD 2000/2002"], swap_endian=0 +signature file-magic-auto145 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1015)/ +} + +# >0 string,=AC1018 (len=6), ["DWG AutoDesk AutoCAD 2004/2005/2006"], swap_endian=0 +signature file-magic-auto146 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1018)/ +} + +# >0 string,=AC1021 (len=6), ["DWG AutoDesk AutoCAD 2007/2008/2009"], swap_endian=0 +signature file-magic-auto147 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1021)/ +} + +# >0 string,=AC1024 (len=6), ["DWG AutoDesk AutoCAD 2010/2011/2012"], swap_endian=0 +signature file-magic-auto148 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1024)/ +} + +# >0 string,=AC1027 (len=6), ["DWG AutoDesk AutoCAD 2013/2014"], swap_endian=0 +signature file-magic-auto149 { + file-mime "image/vnd.dwg", 90 + file-magic /(AC1027)/ +} + +# >0 string,=7z\274\257'\034 (len=6), ["7-zip archive data,"], swap_endian=0 +# >>7 byte&,x, [".%d"], swap_endian=0 +signature file-magic-auto150 { + file-mime "application/x-7z-compressed", 1 + file-magic /(7z\xbc\xaf\x27\x1c)(.{1})(.{1})/ +} + +# >0 ustring,=\3757zXZ\000 (len=6), ["XZ compressed data"], swap_endian=0 +signature file-magic-auto151 { + file-mime "application/x-xz", 90 + file-magic /(\xfd7zXZ\x00)/ +} + +# >0 string,=0 string,=GIF94z (len=6), ["ZIF image (GIF+deflate alpha)"], swap_endian=0 +signature file-magic-auto153 { + file-mime "image/x-unknown", 90 + file-magic /(GIF94z)/ +} + +# >0 string,=FGF95a (len=6), ["FGF image (GIF+deflate beta)"], swap_endian=0 +signature file-magic-auto154 { + file-mime "image/x-unknown", 90 + file-magic /(FGF95a)/ +} + +# >0 string/t,=# xmcd (len=6), ["xmcd database file for kscd"], swap_endian=0 +signature file-magic-auto155 { + file-mime "text/x-xmcd", 90 + file-magic /(\x23 xmcd)/ +} + +# >0 string/b,=\333\245-\000\000\000 (len=6), ["Microsoft Office Document"], swap_endian=0 +signature file-magic-auto156 { + file-mime "application/msword", 90 + file-magic /(\xdb\xa5\x2d\x00\x00\x00)/ +} + +# >2 string,=MMXPR3 (len=6), ["Motorola Quark Express Document (English)"], swap_endian=0 +signature file-magic-auto157 { + file-mime "application/x-quark-xpress-3", 90 + file-magic /(.{2})(MMXPR3)/ +} + +# >0 search/1,=P1 (len=2), [""], swap_endian=0 +# >>3 regex,=[0-9]{1,50} (len=12), [", size = %sx"], swap_endian=0 +# >>>3 regex,= [0-9]{1,50} (len=12), ["%s"], swap_endian=0 +signature file-magic-auto158 { + file-mime "image/x-portable-bitmap", 42 + file-magic /(.*)(P1)([0-9]{1,50} )( [0-9]{1,50})/ +} + +# >0 search/1,=P3 (len=2), [""], swap_endian=0 +# >>3 regex,=[0-9]{1,50} (len=12), [", size = %sx"], swap_endian=0 +# >>>3 regex,= [0-9]{1,50} (len=12), ["%s"], swap_endian=0 +signature file-magic-auto159 { + file-mime "image/x-portable-pixmap", 42 + file-magic /(.*)(P3)([0-9]{1,50} )( [0-9]{1,50})/ +} + +# >0 search/1,=P2 (len=2), [""], swap_endian=0 +# >>3 regex,=[0-9]{1,50} (len=12), [", size = %sx"], swap_endian=0 +# >>>3 regex,= [0-9]{1,50} (len=12), ["%s"], swap_endian=0 +signature file-magic-auto160 { + file-mime "image/x-portable-greymap", 42 + file-magic /(.*)(P2)([0-9]{1,50} )( [0-9]{1,50})/ +} + +# >0 string/t,=>20 search/400,= xmlns= (len=7), [""], swap_endian=0 +# >>>&0 regex,=['"]http://earth.google.com/kml (len=31), ["Google KML document"], swap_endian=0 +signature file-magic-auto161 { + file-mime "application/vnd.google-earth.kml+xml", 61 + file-magic /(\x3c\x3fxml)(.{15})(.*)( xmlns\x3d)(['"]http:\x2f\x2fearth.google.com\x2fkml)/ +} + +# >0 string/t,=>20 search/400,= xmlns= (len=7), [""], swap_endian=0 +# >>>&0 regex,=['"]http://www.opengis.net/kml (len=30), ["OpenGIS KML document"], swap_endian=0 +signature file-magic-auto162 { + file-mime "application/vnd.google-earth.kml+xml", 60 + file-magic /(\x3c\x3fxml)(.{15})(.*)( xmlns\x3d)(['"]http:\x2f\x2fwww.opengis.net\x2fkml)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>30 regex,=[Content_Types].xml|_rels/.rels (len=31), [""], swap_endian=0 +# >>>18 (lelong,+49), search/2000,=PK\003\004 (len=4), [""], swap_endian=0 +# >>>>&26 search/1000,=PK\003\004 (len=4), [""], swap_endian=0 +# >>>>>&26 string,=word/ (len=5), ["Microsoft Word 2007+"], swap_endian=0 +signature file-magic-auto163 { + file-mime "application/vnd.openxmlformats-officedocument.wordprocessingml.document", 80 + file-magic /(PK\x03\x04)(.{26})(\[Content_Types\].xml|_rels\x2f.rels)(.*)(PK\x03\x04)(.{26})(.*)(PK\x03\x04)(.{26})(word\x2f)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>30 regex,=[Content_Types].xml|_rels/.rels (len=31), [""], swap_endian=0 +# >>>18 (lelong,+49), search/2000,=PK\003\004 (len=4), [""], swap_endian=0 +# >>>>&26 search/1000,=PK\003\004 (len=4), [""], swap_endian=0 +# >>>>>&26 string,=ppt/ (len=4), ["Microsoft PowerPoint 2007+"], swap_endian=0 +signature file-magic-auto164 { + file-mime "application/vnd.openxmlformats-officedocument.presentationml.presentation", 70 + file-magic /(PK\x03\x04)(.{26})(\[Content_Types\].xml|_rels\x2f.rels)(.*)(PK\x03\x04)(.{26})(.*)(PK\x03\x04)(.{26})(ppt\x2f)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>30 regex,=[Content_Types].xml|_rels/.rels (len=31), [""], swap_endian=0 +# >>>18 (lelong,+49), search/2000,=PK\003\004 (len=4), [""], swap_endian=0 +# >>>>&26 search/1000,=PK\003\004 (len=4), [""], swap_endian=0 +# >>>>>&26 string,=xl/ (len=3), ["Microsoft Excel 2007+"], swap_endian=0 +signature file-magic-auto165 { + file-mime "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", 60 + file-magic /(PK\x03\x04)(.{26})(\[Content_Types\].xml|_rels\x2f.rels)(.*)(PK\x03\x04)(.{26})(.*)(PK\x03\x04)(.{26})(xl\x2f)/ +} + +# >60 string,=RINEX (len=5), [""], swap_endian=0 +# >>80 search/256,=XXRINEXB (len=8), ["RINEX Data, GEO SBAS Broadcast"], swap_endian=0 +# >>>5 string,x, [", version %6.6s"], swap_endian=0 +signature file-magic-auto166 { + file-mime "rinex/broadcast", 1 + file-magic /(.{60})(RINEX)(.{15})(.*)(XXRINEXB)/ +} + +# >60 string,=RINEX (len=5), [""], swap_endian=0 +# >>80 search/256,=XXRINEXD (len=8), ["RINEX Data, Observation (Hatanaka comp)"], swap_endian=0 +# >>>5 string,x, [", version %6.6s"], swap_endian=0 +signature file-magic-auto167 { + file-mime "rinex/observation", 1 + file-magic /(.{60})(RINEX)(.{15})(.*)(XXRINEXD)/ +} + +# >60 string,=RINEX (len=5), [""], swap_endian=0 +# >>80 search/256,=XXRINEXC (len=8), ["RINEX Data, Clock"], swap_endian=0 +# >>>5 string,x, [", version %6.6s"], swap_endian=0 +signature file-magic-auto168 { + file-mime "rinex/clock", 1 + file-magic /(.{60})(RINEX)(.{15})(.*)(XXRINEXC)/ +} + +# >60 string,=RINEX (len=5), [""], swap_endian=0 +# >>80 search/256,=XXRINEXH (len=8), ["RINEX Data, GEO SBAS Navigation"], swap_endian=0 +# >>>5 string,x, [", version %6.6s"], swap_endian=0 +signature file-magic-auto169 { + file-mime "rinex/navigation", 1 + file-magic /(.{60})(RINEX)(.{15})(.*)(XXRINEXH)/ +} + +# >60 string,=RINEX (len=5), [""], swap_endian=0 +# >>80 search/256,=XXRINEXG (len=8), ["RINEX Data, GLONASS Navigation"], swap_endian=0 +# >>>5 string,x, [", version %6.6s"], swap_endian=0 +signature file-magic-auto170 { + file-mime "rinex/navigation", 1 + file-magic /(.{60})(RINEX)(.{15})(.*)(XXRINEXG)/ +} + +# >60 string,=RINEX (len=5), [""], swap_endian=0 +# >>80 search/256,=XXRINEXL (len=8), ["RINEX Data, Galileo Navigation"], swap_endian=0 +# >>>5 string,x, [", version %6.6s"], swap_endian=0 +signature file-magic-auto171 { + file-mime "rinex/navigation", 1 + file-magic /(.{60})(RINEX)(.{15})(.*)(XXRINEXL)/ +} + +# >60 string,=RINEX (len=5), [""], swap_endian=0 +# >>80 search/256,=XXRINEXM (len=8), ["RINEX Data, Meteorological"], swap_endian=0 +# >>>5 string,x, [", version %6.6s"], swap_endian=0 +signature file-magic-auto172 { + file-mime "rinex/meteorological", 1 + file-magic /(.{60})(RINEX)(.{15})(.*)(XXRINEXM)/ +} + +# >60 string,=RINEX (len=5), [""], swap_endian=0 +# >>80 search/256,=XXRINEXN (len=8), ["RINEX Data, Navigation "], swap_endian=0 +# >>>5 string,x, [", version %6.6s"], swap_endian=0 +signature file-magic-auto173 { + file-mime "rinex/navigation", 1 + file-magic /(.{60})(RINEX)(.{15})(.*)(XXRINEXN)/ +} + +# >60 string,=RINEX (len=5), [""], swap_endian=0 +# >>80 search/256,=XXRINEXO (len=8), ["RINEX Data, Observation"], swap_endian=0 +# >>>5 string,x, [", version %6.6s"], swap_endian=0 +signature file-magic-auto174 { + file-mime "rinex/observation", 1 + file-magic /(.{60})(RINEX)(.{15})(.*)(XXRINEXO)/ +} + +# Doubt it's going to be common to have this many bytes buffered. +# >37633 string,=CD001 (len=5), ["ISO 9660 CD-ROM filesystem data (raw 2352 byte sectors)"], swap_endian=0 +#signature file-magic-auto175 { +# file-mime "application/x-iso9660-image", 80 +# file-magic /(.{37633})(CD001)/ +#} + +# >2 string,=-lhd- (len=5), ["LHa 2.x? archive data [lhd]"], swap_endian=0 +signature file-magic-auto176 { + file-mime "application/x-lha", 80 + file-magic /(.{2})(\x2dlhd\x2d)/ +} + +# >0 string,=WARC/ (len=5), ["WARC Archive"], swap_endian=0 +# >>5 string,x, ["version %.4s"], swap_endian=0 +signature file-magic-auto177 { + file-mime "application/warc", 1 + file-magic /(WARC\x2f)(.{0})/ +} + +# >0 string,=AC1.3 (len=5), ["DWG AutoDesk AutoCAD Release 1.3"], swap_endian=0 +signature file-magic-auto178 { + file-mime "image/vnd.dwg", 80 + file-magic /(AC1\x2e3)/ +} + +# >2 string,=-lh - (len=5), ["LHa 2.x? archive data [lh ]"], swap_endian=0 +signature file-magic-auto179 { + file-mime "application/x-lha", 80 + file-magic /(.{2})(\x2dlh \x2d)/ +} + +# >0 string,=AC1.2 (len=5), ["DWG AutoDesk AutoCAD Release 1.2"], swap_endian=0 +signature file-magic-auto180 { + file-mime "image/vnd.dwg", 80 + file-magic /(AC1\x2e2)/ +} + +# >0 string,=MC0.0 (len=5), ["DWG AutoDesk AutoCAD Release 1.0"], swap_endian=0 +signature file-magic-auto181 { + file-mime "image/vnd.dwg", 80 + file-magic /(MC0\x2e0)/ +} + +# >2 string,=-lzs- (len=5), ["LHa/LZS archive data [lzs]"], swap_endian=0 +signature file-magic-auto182 { + file-mime "application/x-lha", 80 + file-magic /(.{2})(\x2dlzs\x2d)/ +} + +# >2 string,=-lz5- (len=5), ["LHarc 1.x archive data [lz5]"], swap_endian=0 +signature file-magic-auto183 { + file-mime "application/x-lharc", 80 + file-magic /(.{2})(\x2dlz5\x2d)/ +} + +# Doubt it's going to be common to have this many bytes buffered. +# >32769 string,=CD001 (len=5), ["#"], swap_endian=0 +#signature file-magic-auto184 { +# file-mime "application/x-iso9660-image", 80 +# file-magic /(.{32769})(CD001)/ +#} + +# >2 string,=-lh3- (len=5), ["LHa 2.x? archive data [lh3]"], swap_endian=0 +signature file-magic-auto185 { + file-mime "application/x-lha", 80 + file-magic /(.{2})(\x2dlh3\x2d)/ +} + +# >2 string,=-lh2- (len=5), ["LHa 2.x? archive data [lh2]"], swap_endian=0 +signature file-magic-auto186 { + file-mime "application/x-lha", 80 + file-magic /(.{2})(\x2dlh2\x2d)/ +} + +# >0 string,=\000\001\000\000\000 (len=5), ["TrueType font data"], swap_endian=0 +signature file-magic-auto187 { + file-mime "application/x-font-ttf", 80 + file-magic /(\x00\x01\x00\x00\x00)/ +} + +# >0 string/b,=PO^Q` (len=5), ["Microsoft Word 6.0 Document"], swap_endian=0 +signature file-magic-auto188 { + file-mime "application/msword", 80 + file-magic /(PO\x5eQ\x60)/ +} + +# >0 string,=%PDF- (len=5), ["PDF document"], swap_endian=0 +signature file-magic-auto189 { + file-mime "application/pdf", 80 + file-magic /(\x25PDF\x2d)/ +} + +# >2114 string,=Biff5 (len=5), ["Microsoft Excel 5.0 Worksheet"], swap_endian=0 +signature file-magic-auto190 { + file-mime "application/vnd.ms-excel", 80 + file-magic /(.{2114})(Biff5)/ +} + +# >2121 string,=Biff5 (len=5), ["Microsoft Excel 5.0 Worksheet"], swap_endian=0 +signature file-magic-auto191 { + file-mime "application/vnd.ms-excel", 80 + file-magic /(.{2121})(Biff5)/ +} + +# >0 string/t,=Path: (len=5), ["news text"], swap_endian=0 +signature file-magic-auto192 { + file-mime "message/news", 80 + file-magic /(Path\x3a)/ +} + +# >0 string/t,=Xref: (len=5), ["news text"], swap_endian=0 +signature file-magic-auto193 { + file-mime "message/news", 80 + file-magic /(Xref\x3a)/ +} + +# >0 string/t,=From: (len=5), ["news or mail text"], swap_endian=0 +signature file-magic-auto194 { + file-mime "message/rfc822", 80 + file-magic /(From\x3a)/ +} + +# >2 string,=-lh7- (len=5), ["LHa (2.x)/LHark archive data [lh7]"], swap_endian=0 +signature file-magic-auto195 { + file-mime "application/x-lha", 80 + file-magic /(.{2})(\x2dlh7\x2d)/ +} + +# >0 string,={\rtf (len=5), ["Rich Text Format data,"], swap_endian=0 +signature file-magic-auto196 { + file-mime "text/rtf", 80 + file-magic /(\x7b\x5crtf)/ +} + +# >2 string,=-lh6- (len=5), ["LHa (2.x) archive data [lh6]"], swap_endian=0 +signature file-magic-auto197 { + file-mime "application/x-lha", 80 + file-magic /(.{2})(\x2dlh6\x2d)/ +} + +# >2 string,=-lh5- (len=5), ["LHa (2.x) archive data [lh5]"], swap_endian=0 +signature file-magic-auto198 { + file-mime "application/x-lha", 80 + file-magic /(.{2})(\x2dlh5\x2d)/ +} + +# >2 string,=-lh4- (len=5), ["LHa (2.x) archive data [lh4]"], swap_endian=0 +signature file-magic-auto199 { + file-mime "application/x-lha", 80 + file-magic /(.{2})(\x2dlh4\x2d)/ +} + +# >2 string,=-lz4- (len=5), ["LHarc 1.x archive data [lz4]"], swap_endian=0 +signature file-magic-auto200 { + file-mime "application/x-lharc", 80 + file-magic /(.{2})(\x2dlz4\x2d)/ +} + +# >2 string,=-lh1- (len=5), ["LHarc 1.x/ARX archive data [lh1]"], swap_endian=0 +signature file-magic-auto201 { + file-mime "application/x-lharc", 80 + file-magic /(.{2})(\x2dlh1\x2d)/ +} + +# >2 string,=-lh0- (len=5), ["LHarc 1.x/ARX archive data [lh0]"], swap_endian=0 +signature file-magic-auto202 { + file-mime "application/x-lharc", 80 + file-magic /(.{2})(\x2dlh0\x2d)/ +} + +# >0 string,=%FDF- (len=5), ["FDF document"], swap_endian=0 +signature file-magic-auto203 { + file-mime "application/vnd.fdf", 80 + file-magic /(\x25FDF\x2d)/ +} + +# >0 belong&,=443 (0x000001bb), [""], swap_endian=0 +signature file-magic-auto204 { + file-mime "video/mpeg", 71 + file-magic /(\x00\x00\x01\xbb)/ +} + +# The non-sequential offsets and use of bitmask and relational operators +# made this difficult to autogenerate. Can see about manually creating +# the correct character class later. +# >0 ubelong&fff8fe00,=167772160 (0x0a000000), [""], swap_endian=0 +# >>3 ubyte&,>0x00, [""], swap_endian=0 +# >>>1 ubyte&,<0x06, [""], swap_endian=0 +# >>>>1 ubyte&,!0x01, ["PCX"], swap_endian=0 +#signature file-magic-auto205 { +# file-mime "image/x-pcx", 1 +# file-magic /(.{4})(.*)([\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])(.*)([\x00\x01\x02\x03\x04\x05])(.*)([\x00\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +#} + +# >0 belong&,=432 (0x000001b0), [""], swap_endian=0 +signature file-magic-auto206 { + file-mime "video/mp4v-es", 71 + file-magic /(\x00\x00\x01\xb0)/ +} + +# >0 belong&,=437 (0x000001b5), [""], swap_endian=0 +signature file-magic-auto207 { + file-mime "video/mp4v-es", 71 + file-magic /(\x00\x00\x01\xb5)/ +} + +# >0 string,=AWBM (len=4), [""], swap_endian=0 +# >>4 leshort&,<1981 (0x07bd), ["Award BIOS bitmap"], swap_endian=0 +signature file-magic-auto208 { + file-mime "image/x-award-bmp", 20 + file-magic /(AWBM)(.{2})/ +} + +# >0 belong&,=435 (0x000001b3), [""], swap_endian=0 +signature file-magic-auto209 { + file-mime "video/mpv", 71 + file-magic /(\x00\x00\x01\xb3)/ +} + +# Converting bitmask to character class might make the regex +# unfriendly to humans. +# >0 belong&ffffffffff5fff10,=1195376656 (0x47400010), [""], swap_endian=0 +#signature file-magic-auto210 { +# file-mime "video/mp2t", 71 +# file-magic /(.{4})/ +#} + +# >0 belong&,=1 (0x00000001), [""], swap_endian=0 +# >>4 byte&0000001f,=0x07, [""], swap_endian=0 +signature file-magic-auto211 { + file-mime "video/h264", 41 + file-magic /(\x00\x00\x00\x01)([\x07\x27\x47\x67\x87\xa7\xc7\xe7])/ +} + +# >0 belong&,=-889275714 (0xcafebabe), [""], swap_endian=0 +signature file-magic-auto212 { + file-mime "application/x-java-applet", 71 + file-magic /(\xca\xfe\xba\xbe)/ +} + +# >0 belong&ffffffffffffff00,=256 (0x00000100), [""], swap_endian=0 +# >>3 byte&,=0xba, ["MPEG sequence"], swap_endian=0 +signature file-magic-auto213 { + file-mime "video/mpeg", 40 + file-magic /(\x00\x00\x01\xba)/ +} + +# >0 belong&ffffffffffffff00,=256 (0x00000100), [""], swap_endian=0 +# >>3 byte&,=0xb0, ["MPEG sequence, v4"], swap_endian=0 +signature file-magic-auto214 { + file-mime "video/mpeg4-generic", 40 + file-magic /(\x00\x00\x01\xb0)/ +} + +# >0 belong&ffffffffffffff00,=256 (0x00000100), [""], swap_endian=0 +# >>3 byte&,=0xb5, ["MPEG sequence, v4"], swap_endian=0 +signature file-magic-auto215 { + file-mime "video/mpeg4-generic", 40 + file-magic /(\x00\x00\x01\xb5)/ +} + +# >0 belong&ffffffffffffff00,=256 (0x00000100), [""], swap_endian=0 +# >>3 byte&,=0xb3, ["MPEG sequence"], swap_endian=0 +signature file-magic-auto216 { + file-mime "video/mpeg", 40 + file-magic /(\x00\x00\x01\xb3)/ +} + +# >0 lelong&,=4 (0x00000004), [""], swap_endian=0 +# >>104 lelong&,=4 (0x00000004), ["X11 SNF font data, LSB first"], swap_endian=0 +signature file-magic-auto217 { + file-mime "application/x-font-sfn", 70 + file-magic /(\x04\x00\x00\x00)(.{100})(\x04\x00\x00\x00)/ +} + +# >0 lelong&00ffffff,=93 (0x0000005d), [""], swap_endian=0 +signature file-magic-auto218 { + file-mime "application/x-lzma", 71 + file-magic /(\x5d\x00\x00.)/ +} + +# This didn't auto-generate correctly due to non-sequential offsets and +# use of bitwise/relational comparisons. At a glance: may not be +# that common/useful, leaving for later. +# >512 ubelong&e0ffff00,=3774873344 (0xe0ffff00), [""], swap_endian=0 +# >>21 ubyte&,<0xe5, ["floppy with old FAT filesystem"], swap_endian=0 +# >>>512 ubyte&,=0xfc, ["180k"], swap_endian=0 +# >>>>2574 ubequad&,=0 (0x0000000000000000), [""], swap_endian=0 +# >>>>>2560 ubequad&,!0 (0x0000000000000000), [""], swap_endian=0 +#signature file-magic-auto219 { +# file-mime "application/x-ima", 2 +# file-magic /(.{512})(.{4})(.*)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4])(.{490})([\xfc])(.{2061})(\x00\x00\x00\x00\x00\x00\x00\x00)(.*)(.{8})/ +#} + +# This didn't auto-generate correctly due to non-sequential offsets and +# use of bitwise/relational comparisons. At a glance: may not be +# that common/useful, leaving for later. +# >512 ubelong&e0ffff00,=3774873344 (0xe0ffff00), [""], swap_endian=0 +# >>21 ubyte&,<0xe5, ["floppy with old FAT filesystem"], swap_endian=0 +# >>>512 ubyte&,=0xfd, [""], swap_endian=0 +# >>>>2574 ubequad&,=0 (0x0000000000000000), [""], swap_endian=0 +#signature file-magic-auto220 { +# file-mime "application/x-ima", 111 +# file-magic /(.{512})(.{4})(.*)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4])(.{490})([\xfd])(.{2061})(\x00\x00\x00\x00\x00\x00\x00\x00)/ +#} + +# This didn't auto-generate correctly due to non-sequential offsets and +# use of bitwise/relational comparisons. At a glance: may not be +# that common/useful, leaving for later. +# >512 ubelong&e0ffff00,=3774873344 (0xe0ffff00), [""], swap_endian=0 +# >>21 ubyte&,<0xe5, ["floppy with old FAT filesystem"], swap_endian=0 +# >>>512 ubyte&,=0xfe, [""], swap_endian=0 +# >>>>1024 ubelong&e0ffff00,=3774873344 (0xe0ffff00), ["160k"], swap_endian=0 +# >>>>>1550 ubequad&,=0 (0x0000000000000000), [""], swap_endian=0 +# >>>>>>1536 ubequad&,!0 (0x0000000000000000), [""], swap_endian=0 +#signature file-magic-auto221 { +# file-mime "application/x-ima", 2 +# file-magic /(.{512})(.{4})(.*)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4])(.{490})([\xfe])(.{511})(.{4})(.{522})(\x00\x00\x00\x00\x00\x00\x00\x00)(.*)(.{8})/ +#} + +# This didn't auto-generate correctly due to non-sequential offsets and +# use of bitwise/relational comparisons. At a glance: may not be +# that common/useful, leaving for later. +# >512 ubelong&e0ffff00,=3774873344 (0xe0ffff00), [""], swap_endian=0 +# >>21 ubyte&,<0xe5, ["floppy with old FAT filesystem"], swap_endian=0 +# >>>512 ubyte&,=0xff, ["320k"], swap_endian=0 +# >>>>1550 ubequad&,=0 (0x0000000000000000), [""], swap_endian=0 +# >>>>>1536 ubequad&,!0 (0x0000000000000000), [""], swap_endian=0 +#signature file-magic-auto222 { +# file-mime "application/x-ima", 2 +# file-magic /(.{512})(.{4})(.*)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4])(.{490})([\xff])(.{1037})(\x00\x00\x00\x00\x00\x00\x00\x00)(.*)(.{8})/ +#} + +# >0 string,=;ELC (len=4), [""], swap_endian=0 +# >>4 byte&,<0x20, ["Emacs/XEmacs v%d byte-compiled Lisp data"], swap_endian=0 +signature file-magic-auto223 { + file-mime "application/x-elc", 10 + file-magic /(\x3bELC)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +} + +# >0 belong&,=440786851 (0x1a45dfa3), [""], swap_endian=0 +# >>4 search/4096,=B\202 (len=2), [""], swap_endian=0 +# >>>&1 string,=webm (len=4), ["WebM"], swap_endian=0 +signature file-magic-auto224 { + file-mime "video/webm", 70 + file-magic /(\x1a\x45\xdf\xa3)(.*)(B\x82)(.{1})(webm)/ +} + +# >0 belong&,=440786851 (0x1a45dfa3), [""], swap_endian=0 +# >>4 search/4096,=B\202 (len=2), [""], swap_endian=0 +# >>>&1 string,=matroska (len=8), ["Matroska data"], swap_endian=0 +signature file-magic-auto225 { + file-mime "video/x-matroska", 110 + file-magic /(\x1a\x45\xdf\xa3)(.*)(B\x82)(.{1})(matroska)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>4 byte&,=0x14, [""], swap_endian=0 +# >>>30 string,=doc.kml (len=7), ["Compressed Google KML Document, including resources."], swap_endian=0 +signature file-magic-auto226 { + file-mime "application/vnd.google-earth.kmz", 100 + file-magic /(PK\x03\x04)([\x14])(.{25})(doc\x2ekml)/ +} + +# The indirect offset in the last magic rule means this has little chance +# Also plenty of bitmasking/relational comparisons that weren't auto-generated. +# of working. +# >0 ulelong&804000e9,=233 (0x000000e9), [""], swap_endian=0 +# >>11 uleshort&000f001f,=0 (0x0000), [""], swap_endian=0 +# >>>11 uleshort&,<32769 (0x8001), [""], swap_endian=0 +# >>>>11 uleshort&,>31 (0x001f), [""], swap_endian=0 +# >>>>>21 ubyte&000000f0,=0xf0, [""], swap_endian=0 +# >>>>>>21 ubyte&,!0xf8, [""], swap_endian=0 +# >>>>>>>54 string,!FAT16 (len=5), [""], swap_endian=0 +# >>>>>>>>11 (leshort,&0), ulelong&00fffff0,=16777200 (0x00fffff0), [", followed by FAT"], swap_endian=0 +#signature file-magic-auto227 { +# file-mime "application/x-ima", 70 +# file-magic /(.{4})(.{7})(.{2})(.*)(.{2})(.*)(.{2})(.{8})([\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])(.*)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf9\xfa\xfb\xfc\xfd\xfe\xff])(.{32})(FAT16)(.{4})/ +#} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=text (len=4), [""], swap_endian=0 +# >>>>>77 byte&,!0x2d, ["Text"], swap_endian=0 +signature file-magic-auto228 { + file-mime "application/vnd.oasis.opendocument.text", 110 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(text)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=text (len=4), [""], swap_endian=0 +# >>>>>77 string,=-template (len=9), ["Text Template"], swap_endian=0 +signature file-magic-auto229 { + file-mime "application/vnd.oasis.opendocument.text-template", 120 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(text)(\x2dtemplate)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=text (len=4), [""], swap_endian=0 +# >>>>>77 string,=-web (len=4), ["HTML Document Template"], swap_endian=0 +signature file-magic-auto230 { + file-mime "application/vnd.oasis.opendocument.text-web", 70 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(text)(\x2dweb)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=text (len=4), [""], swap_endian=0 +# >>>>>77 string,=-master (len=7), ["Master Document"], swap_endian=0 +signature file-magic-auto231 { + file-mime "application/vnd.oasis.opendocument.text-master", 100 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(text)(\x2dmaster)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=graphics (len=8), [""], swap_endian=0 +# >>>>>81 byte&,!0x2d, ["Drawing"], swap_endian=0 +signature file-magic-auto232 { + file-mime "application/vnd.oasis.opendocument.graphics", 110 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(graphics)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=graphics (len=8), [""], swap_endian=0 +# >>>>>81 string,=-template (len=9), ["Template"], swap_endian=0 +signature file-magic-auto233 { + file-mime "application/vnd.oasis.opendocument.graphics-template", 120 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(graphics)(\x2dtemplate)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=presentation (len=12), [""], swap_endian=0 +# >>>>>85 byte&,!0x2d, ["Presentation"], swap_endian=0 +signature file-magic-auto234 { + file-mime "application/vnd.oasis.opendocument.presentation", 110 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(presentation)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=presentation (len=12), [""], swap_endian=0 +# >>>>>85 string,=-template (len=9), ["Template"], swap_endian=0 +signature file-magic-auto235 { + file-mime "application/vnd.oasis.opendocument.presentation-template", 120 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(presentation)(\x2dtemplate)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=spreadsheet (len=11), [""], swap_endian=0 +# >>>>>84 byte&,!0x2d, ["Spreadsheet"], swap_endian=0 +signature file-magic-auto236 { + file-mime "application/vnd.oasis.opendocument.spreadsheet", 110 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(spreadsheet)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=spreadsheet (len=11), [""], swap_endian=0 +# >>>>>84 string,=-template (len=9), ["Template"], swap_endian=0 +signature file-magic-auto237 { + file-mime "application/vnd.oasis.opendocument.spreadsheet-template", 120 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(spreadsheet)(\x2dtemplate)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=chart (len=5), [""], swap_endian=0 +# >>>>>78 byte&,!0x2d, ["Chart"], swap_endian=0 +signature file-magic-auto238 { + file-mime "application/vnd.oasis.opendocument.chart", 110 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(chart)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=chart (len=5), [""], swap_endian=0 +# >>>>>78 string,=-template (len=9), ["Template"], swap_endian=0 +signature file-magic-auto239 { + file-mime "application/vnd.oasis.opendocument.chart-template", 120 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(chart)(\x2dtemplate)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=formula (len=7), [""], swap_endian=0 +# >>>>>80 byte&,!0x2d, ["Formula"], swap_endian=0 +signature file-magic-auto240 { + file-mime "application/vnd.oasis.opendocument.formula", 1110 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(formula)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=formula (len=7), [""], swap_endian=0 +# >>>>>80 string,=-template (len=9), ["Template"], swap_endian=0 +signature file-magic-auto241 { + file-mime "application/vnd.oasis.opendocument.formula-template", 120 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(formula)(\x2dtemplate)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=database (len=8), ["Database"], swap_endian=0 +signature file-magic-auto242 { + file-mime "application/vnd.oasis.opendocument.database", 110 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(database)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=image (len=5), [""], swap_endian=0 +# >>>>>78 byte&,!0x2d, ["Image"], swap_endian=0 +signature file-magic-auto243 { + file-mime "application/vnd.oasis.opendocument.image", 110 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(image)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=vnd.oasis.opendocument. (len=23), ["OpenDocument"], swap_endian=0 +# >>>>73 string,=image (len=5), [""], swap_endian=0 +# >>>>>78 string,=-template (len=9), ["Template"], swap_endian=0 +signature file-magic-auto244 { + file-mime "application/vnd.oasis.opendocument.image-template", 120 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(vnd\x2eoasis\x2eopendocument\x2e)(image)(\x2dtemplate)/ +} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,=epub+zip (len=8), ["EPUB document"], swap_endian=0 +signature file-magic-auto245 { + file-mime "application/epub+zip", 110 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)(epub\x2bzip)/ +} + +# Seems redundant with other zip signature below. +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetypeapplication/ (len=24), [""], swap_endian=0 +# >>>50 string,!epub+zip (len=8), [""], swap_endian=0 +# >>>>50 string,!vnd.oasis.opendocument. (len=23), [""], swap_endian=0 +# >>>>>50 string,!vnd.sun.xml. (len=12), [""], swap_endian=0 +# >>>>>>50 string,!vnd.kde. (len=8), [""], swap_endian=0 +# >>>>>>>38 regex,=[!-OQ-~]+ (len=9), ["Zip data (MIME type "%s"?)"], swap_endian=0 +#signature file-magic-auto246 { +# file-mime "application/zip", 39 +# file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetypeapplication\x2f)/ +#} + +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 string,=\b\000\000\000mimetype (len=12), [""], swap_endian=0 +# >>>38 string,!application/ (len=12), [""], swap_endian=0 +# >>>>38 regex,=[!-OQ-~]+ (len=9), ["Zip data (MIME type "%s"?)"], swap_endian=0 +signature file-magic-auto247 { + file-mime "application/zip", 39 + file-magic /(PK\x03\x04)(.{22})(\x08\x00\x00\x00mimetype)/ +} + +# The indirect offset makes this difficult to convert. +# The (.*) may be too generous. +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 (leshort,+30), leshort&,=-13570 (0xcafe), ["Java archive data (JAR)"], swap_endian=0 +signature file-magic-auto248 { + file-mime "application/java-archive", 50 + file-magic /(PK\x03\x04)(.*)(\xfe\xca)/ +} + +# The indeirect offset and string inequality make this difficult to convert. +# >0 string,=PK\003\004 (len=4), [""], swap_endian=0 +# >>26 (leshort,+30), leshort&,!-13570 (0xcafe), [""], swap_endian=0 +# >>>26 string,!\b\000\000\000mimetype (len=12), ["Zip archive data"], swap_endian=0 +signature file-magic-auto249 { + file-mime "application/zip", 10 + file-magic /(PK\x03\x04)(.{2})/ +} + +# >0 belong&,=442 (0x000001ba), [""], swap_endian=0 +# >>4 byte&,&0x40, [""], swap_endian=0 +signature file-magic-auto250 { + file-mime "video/mp2p", 21 + file-magic /(\x00\x00\x01\xba)([\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +} + +# >0 belong&,=442 (0x000001ba), [""], swap_endian=0 +# >>4 byte&,^0x40, [""], swap_endian=0 +signature file-magic-auto251 { + file-mime "video/mpeg", 21 + file-magic /(\x00\x00\x01\xba)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf])/ +} + +# >0 string,=MOVI (len=4), ["Silicon Graphics movie file"], swap_endian=0 +signature file-magic-auto252 { + file-mime "video/x-sgi-movie", 70 + file-magic /(MOVI)/ +} + +# >4 string,=moov (len=4), ["Apple QuickTime"], swap_endian=0 +signature file-magic-auto253 { + file-mime "video/quicktime", 70 + file-magic /(.{4})(moov)/ +} + +# >4 string,=mdat (len=4), ["Apple QuickTime movie (unoptimized)"], swap_endian=0 +signature file-magic-auto254 { + file-mime "video/quicktime", 70 + file-magic /(.{4})(mdat)/ +} + +# >4 string,=idsc (len=4), ["Apple QuickTime image (fast start)"], swap_endian=0 +signature file-magic-auto255 { + file-mime "image/x-quicktime", 70 + file-magic /(.{4})(idsc)/ +} + +# >4 string,=pckg (len=4), ["Apple QuickTime compressed archive"], swap_endian=0 +signature file-magic-auto256 { + file-mime "application/x-quicktime-player", 70 + file-magic /(.{4})(pckg)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string,=isom (len=4), [", MPEG v4 system, version 1"], swap_endian=0 +signature file-magic-auto257 { + file-mime "video/mp4", 70 + file-magic /(.{4})(ftyp)(isom)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string,=mp41 (len=4), [", MPEG v4 system, version 1"], swap_endian=0 +signature file-magic-auto258 { + file-mime "video/mp4", 70 + file-magic /(.{4})(ftyp)(mp41)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string,=mp42 (len=4), [", MPEG v4 system, version 2"], swap_endian=0 +signature file-magic-auto259 { + file-mime "video/mp4", 70 + file-magic /(.{4})(ftyp)(mp42)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string/W,=jp2 (len=3), [", JPEG 2000"], swap_endian=0 +signature file-magic-auto260 { + file-mime "image/jp2", 60 + file-magic /(.{4})(ftyp)(jp2)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string,=3ge (len=3), [", MPEG v4 system, 3GPP"], swap_endian=0 +signature file-magic-auto261 { + file-mime "video/3gpp", 60 + file-magic /(.{4})(ftyp)(3ge)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string,=3gg (len=3), [", MPEG v4 system, 3GPP"], swap_endian=0 +signature file-magic-auto262 { + file-mime "video/3gpp", 60 + file-magic /(.{4})(ftyp)(3gg)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string,=3gp (len=3), [", MPEG v4 system, 3GPP"], swap_endian=0 +signature file-magic-auto263 { + file-mime "video/3gpp", 60 + file-magic /(.{4})(ftyp)(3gp)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string,=3gs (len=3), [", MPEG v4 system, 3GPP"], swap_endian=0 +signature file-magic-auto264 { + file-mime "video/3gpp", 60 + file-magic /(.{4})(ftyp)(3gs)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string,=3g2 (len=3), [", MPEG v4 system, 3GPP2"], swap_endian=0 +signature file-magic-auto265 { + file-mime "video/3gpp2", 60 + file-magic /(.{4})(ftyp)(3g2)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string,=mmp4 (len=4), [", MPEG v4 system, 3GPP Mobile"], swap_endian=0 +signature file-magic-auto266 { + file-mime "video/mp4", 70 + file-magic /(.{4})(ftyp)(mmp4)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string,=avc1 (len=4), [", MPEG v4 system, 3GPP JVT AVC"], swap_endian=0 +signature file-magic-auto267 { + file-mime "video/3gpp", 70 + file-magic /(.{4})(ftyp)(avc1)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string/W,=M4A (len=3), [", MPEG v4 system, iTunes AAC-LC"], swap_endian=0 +signature file-magic-auto268 { + file-mime "audio/mp4", 60 + file-magic /(.{4})(ftyp)(M4A)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string/W,=M4V (len=3), [", MPEG v4 system, iTunes AVC-LC"], swap_endian=0 +signature file-magic-auto269 { + file-mime "video/mp4", 60 + file-magic /(.{4})(ftyp)(M4V)/ +} + +# >4 string,=ftyp (len=4), ["ISO Media"], swap_endian=0 +# >>8 string/W,=qt (len=2), [", Apple QuickTime movie"], swap_endian=0 +signature file-magic-auto270 { + file-mime "video/quicktime", 50 + file-magic /(.{4})(ftyp)(qt)/ +} + +# >0 string,=Xcur (len=4), ["Xcursor data"], swap_endian=0 +signature file-magic-auto271 { + file-mime "image/x-xcursor", 70 + file-magic /(Xcur)/ +} + +# >0 string,=ADIF (len=4), ["MPEG ADIF, AAC"], swap_endian=0 +signature file-magic-auto272 { + file-mime "audio/x-hx-aac-adif", 70 + file-magic /(ADIF)/ +} + +# >0 belong&,=807842421 (0x3026b275), ["Microsoft ASF"], swap_endian=0 +signature file-magic-auto273 { + file-mime "video/x-ms-asf", 70 + file-magic /(\x30\x26\xb2\x75)/ +} + +# >0 string,=\212MNG (len=4), ["MNG video data,"], swap_endian=0 +signature file-magic-auto274 { + file-mime "video/x-mng", 70 + file-magic /(\x8aMNG)/ +} + +# >0 string,=\213JNG (len=4), ["JNG video data,"], swap_endian=0 +signature file-magic-auto275 { + file-mime "video/x-jng", 70 + file-magic /(\x8bJNG)/ +} + +# >0 string,=MAC (len=4), ["Monkey's Audio compressed format"], swap_endian=0 +signature file-magic-auto276 { + file-mime "audio/x-ape", 70 + file-magic /(MAC )/ +} + +# >36 string,=acsp (len=4), ["ICC Profile"], swap_endian=0 +signature file-magic-auto277 { + file-mime "application/vnd.iccprofile", 70 + file-magic /(.{36})(acsp)/ +} + +# >0 string,=FORM (len=4), ["IFF data"], swap_endian=0 +# >>8 string,=AIFF (len=4), [", AIFF audio"], swap_endian=0 +signature file-magic-auto278 { + file-mime "audio/x-aiff", 70 + file-magic /(FORM)(.{4})(AIFF)/ +} + +# >0 string,=FORM (len=4), ["IFF data"], swap_endian=0 +# >>8 string,=AIFC (len=4), [", AIFF-C compressed audio"], swap_endian=0 +signature file-magic-auto279 { + file-mime "audio/x-aiff", 70 + file-magic /(FORM)(.{4})(AIFC)/ +} + +# >0 string,=FORM (len=4), ["IFF data"], swap_endian=0 +# >>8 string,=8SVX (len=4), [", 8SVX 8-bit sampled sound voice"], swap_endian=0 +signature file-magic-auto280 { + file-mime "audio/x-aiff", 70 + file-magic /(FORM)(.{4})(8SVX)/ +} + +# >0 string,=fLaC (len=4), ["FLAC audio bitstream data"], swap_endian=0 +signature file-magic-auto281 { + file-mime "audio/x-flac", 70 + file-magic /(fLaC)/ +} + +# >0 string,=IIN1 (len=4), ["NIFF image data"], swap_endian=0 +signature file-magic-auto282 { + file-mime "image/x-niff", 70 + file-magic /(IIN1)/ +} + +# >0 string,=MM\000* (len=4), ["TIFF image data, big-endian"], swap_endian=0 +signature file-magic-auto283 { + file-mime "image/tiff", 70 + file-magic /(MM\x00\x2a)/ +} + +# >0 string,=II*\000 (len=4), ["TIFF image data, little-endian"], swap_endian=0 +signature file-magic-auto284 { + file-mime "image/tiff", 70 + file-magic /(II\x2a\x00)/ +} + +# >0 string,=MM\000+ (len=4), ["Big TIFF image data, big-endian"], swap_endian=0 +signature file-magic-auto285 { + file-mime "image/tiff", 70 + file-magic /(MM\x00\x2b)/ +} + +# >0 string,=II+\000 (len=4), ["Big TIFF image data, little-endian"], swap_endian=0 +signature file-magic-auto286 { + file-mime "image/tiff", 70 + file-magic /(II\x2b\x00)/ +} + +# >0 string,=GIF8 (len=4), ["GIF image data"], swap_endian=0 +signature file-magic-auto287 { + file-mime "image/gif", 70 + file-magic /(GIF8)/ +} + +# >128 string,=DICM (len=4), ["DICOM medical imaging data"], swap_endian=0 +signature file-magic-auto288 { + file-mime "application/dicom", 70 + file-magic /(.{128})(DICM)/ +} + +# >0 string,=8BPS (len=4), ["Adobe Photoshop Image"], swap_endian=0 +signature file-magic-auto289 { + file-mime "image/vnd.adobe.photoshop", 70 + file-magic /(8BPS)/ +} + +# >0 string,=IMPM (len=4), ["Impulse Tracker module sound data -"], swap_endian=0 +signature file-magic-auto290 { + file-mime "audio/x-mod", 70 + file-magic /(IMPM)/ +} + +# >0 lelong&,=20000630 (0x01312f76), ["OpenEXR image data,"], swap_endian=0 +signature file-magic-auto291 { + file-mime "image/x-exr", 70 + file-magic /(\x76\x2f\x31\x01)/ +} + +# >0 string,=SDPX (len=4), ["DPX image data, big-endian,"], swap_endian=0 +signature file-magic-auto292 { + file-mime "image/x-dpx", 70 + file-magic /(SDPX)/ +} + +# >0 belong&,=235082497 (0x0e031301), ["Hierarchical Data Format (version 4) data"], swap_endian=0 +signature file-magic-auto293 { + file-mime "application/x-hdf", 70 + file-magic /(\x0e\x03\x13\x01)/ +} + +# >0 string,=CPC\262 (len=4), ["Cartesian Perceptual Compression image"], swap_endian=0 +signature file-magic-auto294 { + file-mime "image/x-cpi", 70 + file-magic /(CPC\xb2)/ +} + +# >0 string,=MMOR (len=4), ["Olympus ORF raw image data, big-endian"], swap_endian=0 +signature file-magic-auto295 { + file-mime "image/x-olympus-orf", 70 + file-magic /(MMOR)/ +} + +# >0 string,=IIRO (len=4), ["Olympus ORF raw image data, little-endian"], swap_endian=0 +signature file-magic-auto296 { + file-mime "image/x-olympus-orf", 70 + file-magic /(IIRO)/ +} + +# >0 string,=IIRS (len=4), ["Olympus ORF raw image data, little-endian"], swap_endian=0 +signature file-magic-auto297 { + file-mime "image/x-olympus-orf", 70 + file-magic /(IIRS)/ +} + +# >0 string,=FOVb (len=4), ["Foveon X3F raw image data"], swap_endian=0 +signature file-magic-auto298 { + file-mime "image/x-x3f", 70 + file-magic /(FOVb)/ +} + +# >0 string,=PDN3 (len=4), ["Paint.NET image data"], swap_endian=0 +signature file-magic-auto299 { + file-mime "image/x-paintnet", 70 + file-magic /(PDN3)/ +} + +# >0 ulelong&,=2712847316 (0xa1b2c3d4), ["tcpdump capture file (little-endian)"], swap_endian=0 +signature file-magic-auto300 { + file-mime "application/vnd.tcpdump.pcap", 70 + file-magic /(\xd4\xc3\xb2\xa1)/ +} + +# >0 ubelong&,=2712847316 (0xa1b2c3d4), ["tcpdump capture file (big-endian)"], swap_endian=0 +signature file-magic-auto301 { + file-mime "application/vnd.tcpdump.pcap", 70 + file-magic /(\xa1\xb2\xc3\xd4)/ +} + +# >0 belong&,=-17957139 (0xfeedfeed), ["Java KeyStore"], swap_endian=0 +signature file-magic-auto302 { + file-mime "application/x-java-keystore", 70 + file-magic /(\xfe\xed\xfe\xed)/ +} + +# >0 belong&,=-825307442 (0xcececece), ["Java JCE KeyStore"], swap_endian=0 +signature file-magic-auto303 { + file-mime "application/x-java-jce-keystore", 70 + file-magic /(\xce\xce\xce\xce)/ +} + +# >1080 string,=32CN (len=4), ["32-channel Taketracker module sound data"], swap_endian=0 +signature file-magic-auto304 { + file-mime "audio/x-mod", 70 + file-magic /(.{1080})(32CN)/ +} + +# >1080 string,=16CN (len=4), ["16-channel Taketracker module sound data"], swap_endian=0 +signature file-magic-auto305 { + file-mime "audio/x-mod", 70 + file-magic /(.{1080})(16CN)/ +} + +# >1080 string,=OKTA (len=4), ["8-channel Octalyzer module sound data"], swap_endian=0 +signature file-magic-auto306 { + file-mime "audio/x-mod", 70 + file-magic /(.{1080})(OKTA)/ +} + +# >1080 string,=CD81 (len=4), ["8-channel Octalyser module sound data"], swap_endian=0 +signature file-magic-auto307 { + file-mime "audio/x-mod", 70 + file-magic /(.{1080})(CD81)/ +} + +# >1080 string,=8CHN (len=4), ["8-channel Fasttracker module sound data"], swap_endian=0 +signature file-magic-auto308 { + file-mime "audio/x-mod", 70 + file-magic /(.{1080})(8CHN)/ +} + +# >1080 string,=6CHN (len=4), ["6-channel Fasttracker module sound data"], swap_endian=0 +signature file-magic-auto309 { + file-mime "audio/x-mod", 70 + file-magic /(.{1080})(6CHN)/ +} + +# >1080 string,=4CHN (len=4), ["4-channel Fasttracker module sound data"], swap_endian=0 +signature file-magic-auto310 { + file-mime "audio/x-mod", 70 + file-magic /(.{1080})(4CHN)/ +} + +# >1080 string,=FLT8 (len=4), ["8-channel Startracker module sound data"], swap_endian=0 +signature file-magic-auto311 { + file-mime "audio/x-mod", 70 + file-magic /(.{1080})(FLT8)/ +} + +# >1080 string,=FLT4 (len=4), ["4-channel Startracker module sound data"], swap_endian=0 +signature file-magic-auto312 { + file-mime "audio/x-mod", 70 + file-magic /(.{1080})(FLT4)/ +} + +# >1080 string,=M!K! (len=4), ["4-channel Protracker module sound data"], swap_endian=0 +signature file-magic-auto313 { + file-mime "audio/x-mod", 70 + file-magic /(.{1080})(M\x21K\x21)/ +} + +# >1080 string,=M.K. (len=4), ["4-channel Protracker module sound data"], swap_endian=0 +signature file-magic-auto314 { + file-mime "audio/x-mod", 70 + file-magic /(.{1080})(M\x2eK\x2e)/ +} + +# >0 lelong&,=336851773 (0x1413f33d), ["SYSLINUX' LSS16 image data"], swap_endian=0 +signature file-magic-auto315 { + file-mime "image/x-lss16", 70 + file-magic /(\x3d\xf3\x13\x14)/ +} + +# >0 belong&,=779248125 (0x2e7261fd), ["RealAudio sound file"], swap_endian=0 +signature file-magic-auto316 { + file-mime "audio/x-pn-realaudio", 70 + file-magic /(\x2e\x72\x61\xfd)/ +} + +# >0 string,=CTMF (len=4), ["Creative Music (CMF) data"], swap_endian=0 +signature file-magic-auto317 { + file-mime "audio/x-unknown", 70 + file-magic /(CTMF)/ +} + +# >0 string,=MThd (len=4), ["Standard MIDI data"], swap_endian=0 +signature file-magic-auto318 { + file-mime "audio/midi", 70 + file-magic /(MThd)/ +} + +# >0 lelong&,=6583086 (0x0064732e), ["DEC audio data:"], swap_endian=0 +# >>12 lelong&,=1 (0x00000001), ["8-bit ISDN mu-law,"], swap_endian=0 +signature file-magic-auto319 { + file-mime "audio/x-dec-basic", 70 + file-magic /(\x2e\x73\x64\x00)(.{8})(\x01\x00\x00\x00)/ +} + +# >0 lelong&,=6583086 (0x0064732e), ["DEC audio data:"], swap_endian=0 +# >>12 lelong&,=2 (0x00000002), ["8-bit linear PCM [REF-PCM],"], swap_endian=0 +signature file-magic-auto320 { + file-mime "audio/x-dec-basic", 70 + file-magic /(\x2e\x73\x64\x00)(.{8})(\x02\x00\x00\x00)/ +} + +# >0 lelong&,=6583086 (0x0064732e), ["DEC audio data:"], swap_endian=0 +# >>12 lelong&,=3 (0x00000003), ["16-bit linear PCM,"], swap_endian=0 +signature file-magic-auto321 { + file-mime "audio/x-dec-basic", 70 + file-magic /(\x2e\x73\x64\x00)(.{8})(\x03\x00\x00\x00)/ +} + +# >0 lelong&,=6583086 (0x0064732e), ["DEC audio data:"], swap_endian=0 +# >>12 lelong&,=4 (0x00000004), ["24-bit linear PCM,"], swap_endian=0 +signature file-magic-auto322 { + file-mime "audio/x-dec-basic", 70 + file-magic /(\x2e\x73\x64\x00)(.{8})(\x04\x00\x00\x00)/ +} + +# >0 lelong&,=6583086 (0x0064732e), ["DEC audio data:"], swap_endian=0 +# >>12 lelong&,=5 (0x00000005), ["32-bit linear PCM,"], swap_endian=0 +signature file-magic-auto323 { + file-mime "audio/x-dec-basic", 70 + file-magic /(\x2e\x73\x64\x00)(.{8})(\x05\x00\x00\x00)/ +} + +# >0 lelong&,=6583086 (0x0064732e), ["DEC audio data:"], swap_endian=0 +# >>12 lelong&,=6 (0x00000006), ["32-bit IEEE floating point,"], swap_endian=0 +signature file-magic-auto324 { + file-mime "audio/x-dec-basic", 70 + file-magic /(\x2e\x73\x64\x00)(.{8})(\x06\x00\x00\x00)/ +} + +# >0 lelong&,=6583086 (0x0064732e), ["DEC audio data:"], swap_endian=0 +# >>12 lelong&,=7 (0x00000007), ["64-bit IEEE floating point,"], swap_endian=0 +signature file-magic-auto325 { + file-mime "audio/x-dec-basic", 70 + file-magic /(\x2e\x73\x64\x00)(.{8})(\x07\x00\x00\x00)/ +} + +# >0 lelong&,=6583086 (0x0064732e), ["DEC audio data:"], swap_endian=0 +# >>12 lelong&,=23 (0x00000017), ["8-bit ISDN mu-law compressed (CCITT G.721 ADPCM voice enc.),"], swap_endian=0 +signature file-magic-auto326 { + file-mime "audio/x-dec-basic", 70 + file-magic /(\x2e\x73\x64\x00)(.{8})(\x17\x00\x00\x00)/ +} + +# >0 string,=.snd (len=4), ["Sun/NeXT audio data:"], swap_endian=0 +# >>12 belong&,=1 (0x00000001), ["8-bit ISDN mu-law,"], swap_endian=0 +signature file-magic-auto327 { + file-mime "audio/basic", 70 + file-magic /(\x2esnd)(.{8})(\x00\x00\x00\x01)/ +} + +# >0 string,=.snd (len=4), ["Sun/NeXT audio data:"], swap_endian=0 +# >>12 belong&,=2 (0x00000002), ["8-bit linear PCM [REF-PCM],"], swap_endian=0 +signature file-magic-auto328 { + file-mime "audio/basic", 70 + file-magic /(\x2esnd)(.{8})(\x00\x00\x00\x02)/ +} + +# >0 string,=.snd (len=4), ["Sun/NeXT audio data:"], swap_endian=0 +# >>12 belong&,=3 (0x00000003), ["16-bit linear PCM,"], swap_endian=0 +signature file-magic-auto329 { + file-mime "audio/basic", 70 + file-magic /(\x2esnd)(.{8})(\x00\x00\x00\x03)/ +} + +# >0 string,=.snd (len=4), ["Sun/NeXT audio data:"], swap_endian=0 +# >>12 belong&,=4 (0x00000004), ["24-bit linear PCM,"], swap_endian=0 +signature file-magic-auto330 { + file-mime "audio/basic", 70 + file-magic /(\x2esnd)(.{8})(\x00\x00\x00\x04)/ +} + +# >0 string,=.snd (len=4), ["Sun/NeXT audio data:"], swap_endian=0 +# >>12 belong&,=5 (0x00000005), ["32-bit linear PCM,"], swap_endian=0 +signature file-magic-auto331 { + file-mime "audio/basic", 70 + file-magic /(\x2esnd)(.{8})(\x00\x00\x00\x05)/ +} + +# >0 string,=.snd (len=4), ["Sun/NeXT audio data:"], swap_endian=0 +# >>12 belong&,=6 (0x00000006), ["32-bit IEEE floating point,"], swap_endian=0 +signature file-magic-auto332 { + file-mime "audio/basic", 70 + file-magic /(\x2esnd)(.{8})(\x00\x00\x00\x06)/ +} + +# >0 string,=.snd (len=4), ["Sun/NeXT audio data:"], swap_endian=0 +# >>12 belong&,=7 (0x00000007), ["64-bit IEEE floating point,"], swap_endian=0 +signature file-magic-auto333 { + file-mime "audio/basic", 70 + file-magic /(\x2esnd)(.{8})(\x00\x00\x00\x07)/ +} + +# >0 string,=.snd (len=4), ["Sun/NeXT audio data:"], swap_endian=0 +# >>12 belong&,=23 (0x00000017), ["8-bit ISDN mu-law compressed (CCITT G.721 ADPCM voice enc.),"], swap_endian=0 +signature file-magic-auto334 { + file-mime "audio/x-adpcm", 70 + file-magic /(\x2esnd)(.{8})(\x00\x00\x00\x17)/ +} + +# >0 string,=SIT! (len=4), ["StuffIt Archive (data)"], swap_endian=0 +signature file-magic-auto335 { + file-mime "application/x-stuffit", 70 + file-magic /(SIT\x21)/ +} + +# >0 lelong&,=574529400 (0x223e9f78), ["Transport Neutral Encapsulation Format"], swap_endian=0 +signature file-magic-auto336 { + file-mime "application/vnd.ms-tnef", 70 + file-magic /(\x78\x9f\x3e\x22)/ +} + +# >0 string,= (len=4), ["System V Release 1 ar archive"], swap_endian=0 +signature file-magic-auto337 { + file-mime "application/x-archive", 70 + file-magic /(\x3car\x3e)/ +} + +# >0 lelong&ffffffff8080ffff,=2074 (0x0000081a), ["ARC archive data, dynamic LZW"], swap_endian=0 +signature file-magic-auto338 { + file-mime "application/x-arc", 70 + file-magic /([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f]{2})(\x08\x1a)/ +} + +# >0 lelong&ffffffff8080ffff,=2330 (0x0000091a), ["ARC archive data, squashed"], swap_endian=0 +signature file-magic-auto339 { + file-mime "application/x-arc", 70 + file-magic /([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f]{2})(\x09\x1a)/ +} + +# >0 lelong&ffffffff8080ffff,=538 (0x0000021a), ["ARC archive data, uncompressed"], swap_endian=0 +signature file-magic-auto340 { + file-mime "application/x-arc", 70 + file-magic /([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f]{2})(\x02\x1a)/ +} + +# >0 lelong&,=270539386 (0x10201a7a), ["Symbian installation file (Symbian OS 9.x)"], swap_endian=0 +signature file-magic-auto341 { + file-mime "x-epoc/x-sisx-app", 70 + file-magic /(\x7a\x1a\x20\x10)/ +} + +# >8 lelong&,=268436505 (0x10000419), ["Symbian installation file"], swap_endian=0 +signature file-magic-auto342 { + file-mime "application/vnd.symbian.install", 70 + file-magic /(.{8})(\x19\x04\x00\x10)/ +} + +# >0 lelong&ffffffff8080ffff,=794 (0x0000031a), ["ARC archive data, packed"], swap_endian=0 +signature file-magic-auto343 { + file-mime "application/x-arc", 70 + file-magic /([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f]{2})(\x03\x1a)/ +} + +# >0 belong&,=518520576 (0x1ee7ff00), ["EET archive"], swap_endian=0 +signature file-magic-auto344 { + file-mime "application/x-eet", 70 + file-magic /(\x1e\xe7\xff\x00)/ +} + +# >0 lelong&ffffffff8080ffff,=1050 (0x0000041a), ["ARC archive data, squeezed"], swap_endian=0 +signature file-magic-auto345 { + file-mime "application/x-arc", 70 + file-magic /([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f]{2})(\x04\x1a)/ +} + +# >0 lelong&ffffffff8080ffff,=1562 (0x0000061a), ["ARC archive data, crunched"], swap_endian=0 +signature file-magic-auto346 { + file-mime "application/x-arc", 70 + file-magic /([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f]{2})(\x06\x1a)/ +} + +# >0 lelong&ffffffff8080ffff,=2586 (0x00000a1a), ["PAK archive data"], swap_endian=0 +signature file-magic-auto347 { + file-mime "application/x-arc", 70 + file-magic /([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f]{2})(\x0a\x1a)/ +} + +# >0 lelong&ffffffff8080ffff,=5146 (0x0000141a), ["ARC+ archive data"], swap_endian=0 +signature file-magic-auto348 { + file-mime "application/x-arc", 70 + file-magic /([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f]{2})(\x14\x1a)/ +} + +# >20 lelong&,=-37443620 (0xfdc4a7dc), ["Zoo archive data"], swap_endian=0 +signature file-magic-auto349 { + file-mime "application/x-zoo", 70 + file-magic /(.{20})(\xdc\xa7\xc4\xfd)/ +} + +# >0 string,=Rar! (len=4), ["RAR archive data,"], swap_endian=0 +signature file-magic-auto350 { + file-mime "application/x-rar", 70 + file-magic /(Rar\x21)/ +} + +# >0 lelong&ffffffff8080ffff,=18458 (0x0000481a), ["HYP archive data"], swap_endian=0 +signature file-magic-auto351 { + file-mime "application/x-arc", 70 + file-magic /([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f]{2})(\x48\x1a)/ +} + +# >0 string,=drpm (len=4), ["Delta RPM"], swap_endian=0 +signature file-magic-auto352 { + file-mime "application/x-rpm", 70 + file-magic /(drpm)/ +} + +# >0 belong&,=-307499301 (0xedabeedb), ["RPM"], swap_endian=0 +signature file-magic-auto353 { + file-mime "application/x-rpm", 70 + file-magic /(\xed\xab\xee\xdb)/ +} + +# >0 string,=RIFF (len=4), ["RIFF (little-endian) data"], swap_endian=0 +# >>8 string,=WAVE (len=4), [", WAVE audio"], swap_endian=0 +signature file-magic-auto354 { + file-mime "audio/x-wav", 70 + file-magic /(RIFF)(.{4})(WAVE)/ +} + +# >0 string,=RIFF (len=4), ["RIFF (little-endian) data"], swap_endian=0 +# >>8 string,=CDRA (len=4), [", Corel Draw Picture"], swap_endian=0 +signature file-magic-auto355 { + file-mime "image/x-coreldraw", 70 + file-magic /(RIFF)(.{4})(CDRA)/ +} + +# >0 string,=RIFF (len=4), ["RIFF (little-endian) data"], swap_endian=0 +# >>8 string,=CDR6 (len=4), [", Corel Draw Picture, version 6"], swap_endian=0 +signature file-magic-auto356 { + file-mime "image/x-coreldraw", 70 + file-magic /(RIFF)(.{4})(CDR6)/ +} + +# >0 string,=RIFF (len=4), ["RIFF (little-endian) data"], swap_endian=0 +# >>8 string,=AVI (len=4), [", AVI"], swap_endian=0 +signature file-magic-auto357 { + file-mime "video/x-msvideo", 70 + file-magic /(RIFF)(.{4})(AVI )/ +} + +# >0 belong&,=834535424 (0x31be0000), ["Microsoft Word Document"], swap_endian=0 +signature file-magic-auto358 { + file-mime "application/msword", 70 + file-magic /(\x31\xbe\x00\x00)/ +} + +# >0 string/b,=\3767\000# (len=4), ["Microsoft Office Document"], swap_endian=0 +signature file-magic-auto359 { + file-mime "application/msword", 70 + file-magic /(\xfe7\x00\x23)/ +} + +# >0 string/b,=\333\245-\000 (len=4), ["Microsoft WinWord 2.0 Document"], swap_endian=0 +signature file-magic-auto360 { + file-mime "application/msword", 70 + file-magic /(\xdb\xa5\x2d\x00)/ +} + +# >0 string/b,=\333\245-\000 (len=4), ["Microsoft WinWord 2.0 Document"], swap_endian=0 +signature file-magic-auto361 { + file-mime "application/msword", 70 + file-magic /(\xdb\xa5\x2d\x00)/ +} + +# >0 belong&,=6656 (0x00001a00), ["Lotus 1-2-3"], swap_endian=0 +signature file-magic-auto362 { + file-mime "application/x-123", 70 + file-magic /(\x00\x00\x1a\x00)/ +} + +# >0 belong&,=512 (0x00000200), ["Lotus 1-2-3"], swap_endian=0 +signature file-magic-auto363 { + file-mime "application/x-123", 70 + file-magic /(\x00\x00\x02\x00)/ +} + +# >0 string/b,=\000\000\001\000 (len=4), ["MS Windows icon resource"], swap_endian=0 +signature file-magic-auto364 { + file-mime "image/x-icon", 70 + file-magic /(\x00\x00\x01\x00)/ +} + +# >0 lelong&,=268435536 (0x10000050), ["Psion Series 5"], swap_endian=0 +# >>4 lelong&,=268435565 (0x1000006d), ["database"], swap_endian=0 +# >>>8 lelong&,=268435588 (0x10000084), ["Agenda file"], swap_endian=0 +signature file-magic-auto365 { + file-mime "application/x-epoc-agenda", 70 + file-magic /(\x50\x00\x00\x10)(\x6d\x00\x00\x10)(\x84\x00\x00\x10)/ +} + +# >0 lelong&,=268435536 (0x10000050), ["Psion Series 5"], swap_endian=0 +# >>4 lelong&,=268435565 (0x1000006d), ["database"], swap_endian=0 +# >>>8 lelong&,=268435590 (0x10000086), ["Data file"], swap_endian=0 +signature file-magic-auto366 { + file-mime "application/x-epoc-data", 70 + file-magic /(\x50\x00\x00\x10)(\x6d\x00\x00\x10)(\x86\x00\x00\x10)/ +} + +# >0 lelong&,=268435536 (0x10000050), ["Psion Series 5"], swap_endian=0 +# >>4 lelong&,=268435565 (0x1000006d), ["database"], swap_endian=0 +# >>>8 lelong&,=268438762 (0x10000cea), ["Jotter file"], swap_endian=0 +signature file-magic-auto367 { + file-mime "application/x-epoc-jotter", 70 + file-magic /(\x50\x00\x00\x10)(\x6d\x00\x00\x10)(\xea\x0c\x00\x10)/ +} + +# >0 lelong&,=268435511 (0x10000037), ["Psion Series 5"], swap_endian=0 +# >>4 lelong&,=268435522 (0x10000042), ["multi-bitmap image"], swap_endian=0 +signature file-magic-auto368 { + file-mime "image/x-epoc-mbm", 70 + file-magic /(\x37\x00\x00\x10)(\x42\x00\x00\x10)/ +} + +# >0 lelong&,=268435511 (0x10000037), ["Psion Series 5"], swap_endian=0 +# >>4 lelong&,=268435565 (0x1000006d), [""], swap_endian=0 +# >>>8 lelong&,=268435581 (0x1000007d), ["Sketch image"], swap_endian=0 +signature file-magic-auto369 { + file-mime "image/x-epoc-sketch", 70 + file-magic /(\x37\x00\x00\x10)(\x6d\x00\x00\x10)(\x7d\x00\x00\x10)/ +} + +# >0 lelong&,=268435511 (0x10000037), ["Psion Series 5"], swap_endian=0 +# >>4 lelong&,=268435565 (0x1000006d), [""], swap_endian=0 +# >>>8 lelong&,=268435583 (0x1000007f), ["Word file"], swap_endian=0 +signature file-magic-auto370 { + file-mime "application/x-epoc-word", 70 + file-magic /(\x37\x00\x00\x10)(\x6d\x00\x00\x10)(\x7f\x00\x00\x10)/ +} + +# >0 lelong&,=268435511 (0x10000037), ["Psion Series 5"], swap_endian=0 +# >>4 lelong&,=268435565 (0x1000006d), [""], swap_endian=0 +# >>>8 lelong&,=268435589 (0x10000085), ["OPL program (TextEd)"], swap_endian=0 +signature file-magic-auto371 { + file-mime "application/x-epoc-opl", 70 + file-magic /(\x37\x00\x00\x10)(\x6d\x00\x00\x10)(\x85\x00\x00\x10)/ +} + +# >0 lelong&,=268435511 (0x10000037), ["Psion Series 5"], swap_endian=0 +# >>4 lelong&,=268435565 (0x1000006d), [""], swap_endian=0 +# >>>8 lelong&,=268435592 (0x10000088), ["Sheet file"], swap_endian=0 +signature file-magic-auto372 { + file-mime "application/x-epoc-sheet", 70 + file-magic /(\x37\x00\x00\x10)(\x6d\x00\x00\x10)(\x88\x00\x00\x10)/ +} + +# >0 lelong&,=268435511 (0x10000037), ["Psion Series 5"], swap_endian=0 +# >>4 lelong&,=268435571 (0x10000073), ["OPO module"], swap_endian=0 +signature file-magic-auto373 { + file-mime "application/x-epoc-opo", 70 + file-magic /(\x37\x00\x00\x10)(\x73\x00\x00\x10)/ +} + +# >0 lelong&,=268435511 (0x10000037), ["Psion Series 5"], swap_endian=0 +# >>4 lelong&,=268435572 (0x10000074), ["OPL application"], swap_endian=0 +signature file-magic-auto374 { + file-mime "application/x-epoc-app", 70 + file-magic /(\x37\x00\x00\x10)(\x74\x00\x00\x10)/ +} + +# >0 long&,=398689 (0x00061561), ["Berkeley DB"], swap_endian=0 +signature file-magic-auto375 { + file-mime "application/x-dbm", 70 + file-magic /((\x61\x15\x06\x00)|(\x00\x06\x15\x61))/ +} + +# >0 string,=GDBM (len=4), ["GNU dbm 2.x database"], swap_endian=0 +signature file-magic-auto376 { + file-mime "application/x-gdbm", 70 + file-magic /(GDBM)/ +} + +# >0 lelong&,=324508366 (0x13579ace), ["GNU dbm 1.x or ndbm database, little endian"], swap_endian=0 +signature file-magic-auto377 { + file-mime "application/x-gdbm", 70 + file-magic /(\xce\x9a\x57\x13)/ +} + +# >0 belong&,=324508366 (0x13579ace), ["GNU dbm 1.x or ndbm database, big endian"], swap_endian=0 +signature file-magic-auto378 { + file-mime "application/x-gdbm", 70 + file-magic /(\x13\x57\x9a\xce)/ +} + +# >0 belong&,=4 (0x00000004), ["X11 SNF font data, MSB first"], swap_endian=0 +signature file-magic-auto379 { + file-mime "application/x-font-sfn", 70 + file-magic /(\x00\x00\x00\x04)/ +} + +# >0 string,=OTTO (len=4), ["OpenType font data"], swap_endian=0 +signature file-magic-auto380 { + file-mime "application/vnd.ms-opentype", 70 + file-magic /(OTTO)/ +} + +# >0 string,=0 lelong&,=407642370 (0x184c2102), ["LZ4 compressed data, legacy format"], swap_endian=0 +signature file-magic-auto382 { + file-mime "application/x-lz4", 70 + file-magic /(\x02\x21\x4c\x18)/ +} + +# >0 lelong&,=407708164 (0x184d2204), ["LZ4 compressed data"], swap_endian=0 +signature file-magic-auto383 { + file-mime "application/x-lz4", 70 + file-magic /(\x04\x22\x4d\x18)/ +} + +# >0 string,=LRZI (len=4), ["LRZIP compressed data"], swap_endian=0 +# >>5 byte&,x, [".%d"], swap_endian=0 +signature file-magic-auto384 { + file-mime "application/x-lrzip", 1 + file-magic /(LRZI)(.{1})(.{1})/ +} + +# >0 string,=OggS (len=4), ["Ogg data"], swap_endian=0 +signature file-magic-auto385 { + file-mime "application/ogg", 70 + file-magic /(OggS)/ +} + +# >0 string,=LZIP (len=4), ["lzip compressed data"], swap_endian=0 +signature file-magic-auto386 { + file-mime "application/x-lzip", 70 + file-magic /(LZIP)/ +} + +# >0 belong&,=-889270259 (0xcafed00d), ["JAR compressed with pack200,"], swap_endian=0 +# >>4 byte&,x, ["%d"], swap_endian=0 +signature file-magic-auto387 { + file-mime "application/x-java-pack200", 1 + file-magic /(\xca\xfe\xd0\x0d)(.{1})/ +} + +# >0 belong&,=-889270259 (0xcafed00d), ["JAR compressed with pack200,"], swap_endian=0 +# >>4 byte&,x, ["%d"], swap_endian=0 +signature file-magic-auto388 { + file-mime "application/x-java-pack200", 1 + file-magic /(\xca\xfe\xd0\x0d)(.{1})/ +} + +# >0 regex,=^( |\t){0,50}def {1,50}[a-zA-Z]{1,100} (len=38), [""], swap_endian=0 +# >>&0 regex,= {0,50}\(([a-zA-Z]|,| ){1,500}\):$ (len=34), ["Python script text executable"], swap_endian=0 +signature file-magic-auto389 { + file-mime "text/x-python", 64 + file-magic /(^( |\t){0,50}def {1,50}[a-zA-Z]{1,100})( {0,50}\(([a-zA-Z]|,| ){1,500}\):$)/ +} + +# >0 search/4096,=\documentstyle (len=14), ["LaTeX document text"], swap_endian=0 +signature file-magic-auto390 { + file-mime "text/x-tex", 62 + file-magic /(.*)(\x5cdocumentstyle)/ +} + +# >0 string,=DOC (len=3), [""], swap_endian=0 +# >>43 byte&,=0x14, ["Just System Word Processor Ichitaro v4"], swap_endian=0 +signature file-magic-auto391 { + file-mime "application/x-ichitaro4", 40 + file-magic /(DOC)(.{40})([\x14])/ +} + +# >0 string,=DOC (len=3), [""], swap_endian=0 +# >>43 byte&,=0x15, ["Just System Word Processor Ichitaro v5"], swap_endian=0 +signature file-magic-auto392 { + file-mime "application/x-ichitaro5", 40 + file-magic /(DOC)(.{40})([\x15])/ +} + +# >1 string,=SaR (len=3), [""], swap_endian=0 +# >>0 string,=3 (len=1), ["Cups Raster version 3, Little Endian"], swap_endian=0 +signature file-magic-auto393 { + file-mime "application/vnd.cups-raster", 40 + file-magic /(3)(SaR)/ +} + +# >0 string,=RaS (len=3), [""], swap_endian=0 +# >>3 string,=3 (len=1), ["Cups Raster version 3, Big Endian"], swap_endian=0 +signature file-magic-auto394 { + file-mime "application/vnd.cups-raster", 40 + file-magic /(RaS)(3)/ +} + +# >0 string,=DOC (len=3), [""], swap_endian=0 +# >>43 byte&,=0x16, ["Just System Word Processor Ichitaro v6"], swap_endian=0 +signature file-magic-auto395 { + file-mime "application/x-ichitaro6", 40 + file-magic /(DOC)(.{40})([\x16])/ +} + +# >0 search/w/1,=#! /usr/local/bin/php (len=21), ["PHP script text executable"], swap_endian=0 +signature file-magic-auto396 { + file-mime "text/x-php", 61 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fphp)/ +} + +# >0 search/1,=eval '(exit $?0)' && eval 'exec (len=31), ["Perl script text"], swap_endian=0 +signature file-magic-auto397 { + file-mime "text/x-perl", 61 + file-magic /(.*)(eval \x27\x28exit \x24\x3f0\x29\x27 \x26\x26 eval \x27exec)/ +} + +# >0 regex,=^[ \t]*require[ \t]'[A-Za-z_/]+' (len=30), [""], swap_endian=0 +# >>0 regex,=include [A-Z]|def [a-z]| do$ (len=28), [""], swap_endian=0 +# >>>0 regex,=^[ \t]*end([ \t]*[;#].*)?$ (len=24), ["Ruby script text"], swap_endian=0 +signature file-magic-auto398 { + file-mime "text/x-ruby", 54 + file-magic /(^[ \x09]*require[ \x09]'[A-Za-z_\x2f]+')(include [A-Z]|def [a-z]| do$)(^[ \x09]*end([ \x09]*[;#].*)?$)/ +} + +# >0 search/1,=eval "exec /usr/local/bin/perl (len=30), ["Perl script text"], swap_endian=0 +signature file-magic-auto399 { + file-mime "text/x-perl", 60 + file-magic /(.*)(eval \x22exec \x2fusr\x2flocal\x2fbin\x2fperl)/ +} + +# >0 string,=FLV (len=3), ["Macromedia Flash Video"], swap_endian=0 +signature file-magic-auto400 { + file-mime "video/x-flv", 60 + file-magic /(FLV)/ +} + +# >0 string,=MP+ (len=3), ["Musepack audio"], swap_endian=0 +signature file-magic-auto401 { + file-mime "audio/x-musepack", 60 + file-magic /(MP\x2b)/ +} + +# >0 string,=PBF (len=3), ["PBF image (deflate compression)"], swap_endian=0 +signature file-magic-auto402 { + file-mime "image/x-unknown", 60 + file-magic /(PBF)/ +} + +# >0 string,=SBI (len=3), ["SoundBlaster instrument data"], swap_endian=0 +signature file-magic-auto403 { + file-mime "audio/x-unknown", 60 + file-magic /(SBI)/ +} + +# >0 string/b,=\224\246. (len=3), ["Microsoft Word Document"], swap_endian=0 +signature file-magic-auto404 { + file-mime "application/msword", 60 + file-magic /(\x94\xa6\x2e)/ +} + +# >0 string,=\004%! (len=3), ["PostScript document text"], swap_endian=0 +signature file-magic-auto405 { + file-mime "application/postscript", 60 + file-magic /(\x04\x25\x21)/ +} + +# >0 string,=BZh (len=3), ["bzip2 compressed data"], swap_endian=0 +signature file-magic-auto406 { + file-mime "application/x-bzip2", 60 + file-magic /(BZh)/ +} + +# >0 regex,=^[ \t]*(class|module)[ \t][A-Z] (len=29), [""], swap_endian=0 +# >>0 regex,=(modul|includ)e [A-Z]|def [a-z] (len=31), [""], swap_endian=0 +# >>>0 regex,=^[ \t]*end([ \t]*[;#].*)?$ (len=24), ["Ruby module source text"], swap_endian=0 +signature file-magic-auto407 { + file-mime "text/x-ruby", 54 + file-magic /(^[ \x09]*(class|module)[ \x09][A-Z])((modul|includ)e [A-Z]|def [a-z])(^[ \x09]*end([ \x09]*[;#].*)?$)/ +} + +# >512 string/b,=\354\245\301 (len=3), ["Microsoft Word Document"], swap_endian=0 +signature file-magic-auto408 { + file-mime "application/msword", 60 + file-magic /(.{512})(\xec\xa5\xc1)/ +} + +# >0 string,=FWS (len=3), ["Macromedia Flash data,"], swap_endian=0 +# >>3 byte&,x, ["version %d"], swap_endian=0 +signature file-magic-auto409 { + file-mime "application/x-shockwave-flash", 1 + file-magic /(FWS)(.{1})/ +} + +# >0 string,=CWS (len=3), ["Macromedia Flash data (compressed),"], swap_endian=0 +signature file-magic-auto410 { + file-mime "application/x-shockwave-flash", 60 + file-magic /(CWS)/ +} + +# >0 regex/20,=^\.[A-Za-z0-9][A-Za-z0-9][ \t] (len=29), ["troff or preprocessor input text"], swap_endian=0 +signature file-magic-auto411 { + file-mime "text/troff", 59 + file-magic /(^\.[A-Za-z0-9][A-Za-z0-9][ \x09])/ +} + +# >0 search/4096,=\documentclass (len=14), ["LaTeX 2e document text"], swap_endian=0 +signature file-magic-auto412 { + file-mime "text/x-tex", 59 + file-magic /(.*)(\x5cdocumentclass)/ +} + +# >0 regex,=^from\s+(\w|\.)+\s+import.*$ (len=28), ["Python script text executable"], swap_endian=0 +signature file-magic-auto413 { + file-mime "text/x-python", 58 + file-magic /(^from\s+(\w|\.)+\s+import.*$)/ +} + +# >0 search/4096,=\contentsline (len=13), ["LaTeX table of contents"], swap_endian=0 +signature file-magic-auto414 { + file-mime "text/x-tex", 58 + file-magic /(.*)(\x5ccontentsline)/ +} + +# >0 search/4096,=\chapter (len=8), ["LaTeX document text"], swap_endian=0 +signature file-magic-auto415 { + file-mime "text/x-tex", 56 + file-magic /(.*)(\x5cchapter)/ +} + +# >0 search/4096,=\section (len=8), ["LaTeX document text"], swap_endian=0 +signature file-magic-auto416 { + file-mime "text/x-tex", 56 + file-magic /(.*)(\x5csection)/ +} + +# >0 regex/20,=^\.[A-Za-z0-9][A-Za-z0-9]$ (len=26), ["troff or preprocessor input text"], swap_endian=0 +signature file-magic-auto417 { + file-mime "text/troff", 56 + file-magic /(^\.[A-Za-z0-9][A-Za-z0-9]$)/ +} + +# >0 search/w/1,=#! /usr/bin/php (len=15), ["PHP script text executable"], swap_endian=0 +signature file-magic-auto418 { + file-mime "text/x-php", 55 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2fbin\x2fphp)/ +} + +# >0 search/4096,=\setlength (len=10), ["LaTeX document text"], swap_endian=0 +signature file-magic-auto419 { + file-mime "text/x-tex", 55 + file-magic /(.*)(\x5csetlength)/ +} + +# >0 search/1,=eval "exec /usr/bin/perl (len=24), ["Perl script text"], swap_endian=0 +signature file-magic-auto420 { + file-mime "text/x-perl", 54 + file-magic /(.*)(eval \x22exec \x2fusr\x2fbin\x2fperl)/ +} + +# >0 search/w/1,=#! /usr/local/bin/python (len=24), ["Python script text executable"], swap_endian=0 +signature file-magic-auto421 { + file-mime "text/x-python", 54 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fpython)/ +} + +# >0 search/1,=Common subdirectories: (len=23), ["diff output text"], swap_endian=0 +signature file-magic-auto422 { + file-mime "text/x-diff", 53 + file-magic /(.*)(Common subdirectories\x3a )/ +} + +# >0 search/1,=#! /usr/bin/env python (len=22), ["Python script text executable"], swap_endian=0 +signature file-magic-auto423 { + file-mime "text/x-python", 52 + file-magic /(.*)(\x23\x21 \x2fusr\x2fbin\x2fenv python)/ +} + +# >0 search/w/1,=#! /usr/local/bin/ruby (len=22), ["Ruby script text executable"], swap_endian=0 +signature file-magic-auto424 { + file-mime "text/x-ruby", 52 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fruby)/ +} + +# >0 search/w/1,=#! /usr/local/bin/wish (len=22), ["Tcl/Tk script text executable"], swap_endian=0 +signature file-magic-auto425 { + file-mime "text/x-tcl", 52 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2fwish)/ +} + +# >0 search/4096,=(custom-set-variables (len=22), ["Lisp/Scheme program text"], swap_endian=0 +signature file-magic-auto426 { + file-mime "text/x-lisp", 52 + file-magic /(.*)(\x28custom\x2dset\x2dvariables )/ +} + +# >0 beshort&,=-40 (0xffd8), ["JPEG image data"], swap_endian=0 +signature file-magic-auto427 { + file-mime "image/jpeg", 52 + file-magic /(\xff\xd8)/ +} + +# >0 search/1,=#!/usr/bin/env python (len=21), ["Python script text executable"], swap_endian=0 +signature file-magic-auto428 { + file-mime "text/x-python", 51 + file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fenv python)/ +} + +# >0 search/1,=#!/usr/bin/env nodejs (len=21), ["Node.js script text executable"], swap_endian=0 +signature file-magic-auto429 { + file-mime "application/javascript", 51 + file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fenv nodejs)/ +} + +# >0 search/w/1,=#! /usr/local/bin/tcl (len=21), ["Tcl script text executable"], swap_endian=0 +signature file-magic-auto430 { + file-mime "text/x-tcl", 51 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2ftcl)/ +} + +# This didn't autogenerate well due to indirect offset, bitmasking, and +# relational comparisons. +# >0 leshort&fffffffffffffefe,=0 (0x0000), [""], swap_endian=0 +# >>4 ulelong&fcfffe00,=0 (0x00000000), [""], swap_endian=0 +# >>>68 ulelong&,>87 (0x00000057), [""], swap_endian=0 +# >>>>68 (lelong,-1), ubelong&ffe0c519,=4194328 (0x00400018), ["Windows Precompiled iNF"], swap_endian=0 +#signature file-magic-auto431 { +# file-mime "application/x-pnf", 70 +# file-magic /(.{2})(.{2})(.{4})(.{60})(.{4})(.{4})/ +#} + +# >0 search/w/1,=#! /usr/local/bin/lua (len=21), ["Lua script text executable"], swap_endian=0 +signature file-magic-auto432 { + file-mime "text/x-lua", 51 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2flocal\x2fbin\x2flua)/ +} + +# >0 string/b,=MZ (len=2), [""], swap_endian=0 +signature file-magic-auto433 { + file-mime "application/x-dosexec", 51 + file-magic /(MZ)/ +} + +# >0 string/b,=MZ (len=2), [""], swap_endian=0 +# >>30 string,=Copyright 1989-1990 PKWARE Inc. (len=31), ["Self-extracting PKZIP archive"], swap_endian=0 +signature file-magic-auto434 { + file-mime "application/zip", 340 + file-magic /(MZ)(.{28})(Copyright 1989\x2d1990 PKWARE Inc\x2e)/ +} + +# >0 string/b,=MZ (len=2), [""], swap_endian=0 +# >>30 string,=PKLITE Copr. (len=12), ["Self-extracting PKZIP archive"], swap_endian=0 +signature file-magic-auto435 { + file-mime "application/zip", 150 + file-magic /(MZ)(.{28})(PKLITE Copr\x2e)/ +} + +# >0 string/b,=MZ (len=2), [""], swap_endian=0 +# >>36 string,=LHa's SFX (len=9), [", LHa self-extracting archive"], swap_endian=0 +signature file-magic-auto436 { + file-mime "application/x-lha", 120 + file-magic /(MZ)(.{34})(LHa\x27s SFX)/ +} + +# >0 string/b,=MZ (len=2), [""], swap_endian=0 +# >>36 string,=LHA's SFX (len=9), [", LHa self-extracting archive"], swap_endian=0 +signature file-magic-auto437 { + file-mime "application/x-lha", 120 + file-magic /(MZ)(.{34})(LHA\x27s SFX)/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0x10, ["MPEG ADTS, layer III, v1, 32 kbps"], swap_endian=0 +signature file-magic-auto438 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0x20, ["MPEG ADTS, layer III, v1, 40 kbps"], swap_endian=0 +signature file-magic-auto439 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0x30, ["MPEG ADTS, layer III, v1, 48 kbps"], swap_endian=0 +signature file-magic-auto440 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0x40, ["MPEG ADTS, layer III, v1, 56 kbps"], swap_endian=0 +signature file-magic-auto441 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0x50, ["MPEG ADTS, layer III, v1, 64 kbps"], swap_endian=0 +signature file-magic-auto442 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0x60, ["MPEG ADTS, layer III, v1, 80 kbps"], swap_endian=0 +signature file-magic-auto443 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0x70, ["MPEG ADTS, layer III, v1, 96 kbps"], swap_endian=0 +signature file-magic-auto444 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0x80, ["MPEG ADTS, layer III, v1, 112 kbps"], swap_endian=0 +signature file-magic-auto445 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0x90, ["MPEG ADTS, layer III, v1, 128 kbps"], swap_endian=0 +signature file-magic-auto446 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0xa0, ["MPEG ADTS, layer III, v1, 160 kbps"], swap_endian=0 +signature file-magic-auto447 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0xb0, ["MPEG ADTS, layer III, v1, 192 kbps"], swap_endian=0 +signature file-magic-auto448 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0xc0, ["MPEG ADTS, layer III, v1, 224 kbps"], swap_endian=0 +signature file-magic-auto449 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0xd0, ["MPEG ADTS, layer III, v1, 256 kbps"], swap_endian=0 +signature file-magic-auto450 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf])/ +} + +# >0 beshort&fffffffffffffffe,=-6 (0xfffa), [""], swap_endian=0 +# >>2 byte&fffffffffffffff0,=0xe0, ["MPEG ADTS, layer III, v1, 320 kbps"], swap_endian=0 +signature file-magic-auto451 { + file-mime "audio/mpeg", 40 + file-magic /(\xff[\xfa\xfb])([\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef])/ +} + +# >4 leshort&,=-20719 (0xaf11), [""], swap_endian=0 +# >>8 leshort&,=320 (0x0140), [""], swap_endian=0 +# >>>10 leshort&,=200 (0x00c8), [""], swap_endian=0 +# >>>>12 leshort&,=8 (0x0008), ["FLI animation, 320x200x8"], swap_endian=0 +signature file-magic-auto452 { + file-mime "video/x-fli", 50 + file-magic /(.{4})(\x11\xaf)(.{2})(\x40\x01)(\xc8\x00)(\x08\x00)/ +} + +# >4 leshort&,=-20718 (0xaf12), [""], swap_endian=0 +# >>12 leshort&,=8 (0x0008), ["FLC animation"], swap_endian=0 +signature file-magic-auto453 { + file-mime "video/x-flc", 50 + file-magic /(.{4})(\x12\xaf)(.{6})(\x08\x00)/ +} + +# >0 string,=BM (len=2), [""], swap_endian=0 +# >>14 leshort&,=12 (0x000c), ["PC bitmap, OS/2 1.x format"], swap_endian=0 +signature file-magic-auto454 { + file-mime "image/x-ms-bmp", 50 + file-magic /(BM)(.{12})(\x0c\x00)/ +} + +# >0 string,=BM (len=2), [""], swap_endian=0 +# >>14 leshort&,=64 (0x0040), ["PC bitmap, OS/2 2.x format"], swap_endian=0 +signature file-magic-auto455 { + file-mime "image/x-ms-bmp", 50 + file-magic /(BM)(.{12})(\x40\x00)/ +} + +# >0 string,=BM (len=2), [""], swap_endian=0 +# >>14 leshort&,=40 (0x0028), ["PC bitmap, Windows 3.x format"], swap_endian=0 +signature file-magic-auto456 { + file-mime "image/x-ms-bmp", 50 + file-magic /(BM)(.{12})(\x28\x00)/ +} + +# >0 string,=BM (len=2), [""], swap_endian=0 +# >>14 leshort&,=124 (0x007c), ["PC bitmap, Windows 98/2000 and newer format"], swap_endian=0 +signature file-magic-auto457 { + file-mime "image/x-ms-bmp", 50 + file-magic /(BM)(.{12})(\x7c\x00)/ +} + +# >0 string,=BM (len=2), [""], swap_endian=0 +# >>14 leshort&,=108 (0x006c), ["PC bitmap, Windows 95/NT4 and newer format"], swap_endian=0 +signature file-magic-auto458 { + file-mime "image/x-ms-bmp", 50 + file-magic /(BM)(.{12})(\x6c\x00)/ +} + +# >0 string,=BM (len=2), [""], swap_endian=0 +# >>14 leshort&,=128 (0x0080), ["PC bitmap, Windows NT/2000 format"], swap_endian=0 +signature file-magic-auto459 { + file-mime "image/x-ms-bmp", 50 + file-magic /(BM)(.{12})(\x80\x00)/ +} + +# >20 string,=45 (len=2), [""], swap_endian=0 +# >>0 regex/1,=(^[0-9]{5})[acdnp][^bhlnqsu-z] (len=30), ["MARC21 Bibliographic"], swap_endian=0 +signature file-magic-auto460 { + file-mime "application/marc", 60 + file-magic /(.{20})(45)(.*)((^[0-9]{5})[acdnp][^bhlnqsu-z])/ +} + +# >20 string,=45 (len=2), [""], swap_endian=0 +# >>0 regex/1,=(^[0-9]{5})[acdnosx][z] (len=23), ["MARC21 Authority"], swap_endian=0 +signature file-magic-auto461 { + file-mime "application/marc", 53 + file-magic /(.{20})(45)(.*)((^[0-9]{5})[acdnosx][z])/ +} + +# >20 string,=45 (len=2), [""], swap_endian=0 +# >>0 regex/1,=(^[0-9]{5})[cdn][uvxy] (len=22), ["MARC21 Holdings"], swap_endian=0 +signature file-magic-auto462 { + file-mime "application/marc", 52 + file-magic /(.{20})(45)(.*)((^[0-9]{5})[cdn][uvxy])/ +} + +# >0 search/4096,=\relax (len=6), ["LaTeX auxiliary file"], swap_endian=0 +signature file-magic-auto463 { + file-mime "text/x-tex", 51 + file-magic /(.*)(\x5crelax)/ +} + +# >0 search/4096,=\begin (len=6), ["LaTeX document text"], swap_endian=0 +signature file-magic-auto464 { + file-mime "text/x-tex", 51 + file-magic /(.*)(\x5cbegin)/ +} + +# >0 search/4096,=\input (len=6), ["TeX document text"], swap_endian=0 +signature file-magic-auto465 { + file-mime "text/x-tex", 51 + file-magic /(.*)(\x5cinput)/ +} + +# >0 leshort&,=-24712 (0x9f78), ["TNEF"], swap_endian=0 +signature file-magic-auto466 { + file-mime "application/vnd.ms-tnef", 50 + file-magic /(\x78\x9f)/ +} + +# >0 leshort&,=-5536 (0xea60), ["ARJ archive data"], swap_endian=0 +signature file-magic-auto467 { + file-mime "application/x-arj", 50 + file-magic /(\x60\xea)/ +} + +# >0 search/1,=eval "exec /bin/perl (len=20), ["Perl script text"], swap_endian=0 +signature file-magic-auto468 { + file-mime "text/x-perl", 50 + file-magic /(.*)(eval \x22exec \x2fbin\x2fperl)/ +} + +# >0 search/1,=#! /usr/bin/env perl (len=20), ["Perl script text executable"], swap_endian=0 +signature file-magic-auto469 { + file-mime "text/x-perl", 50 + file-magic /(.*)(\x23\x21 \x2fusr\x2fbin\x2fenv perl)/ +} + +# >0 beshort&,=-26368 (0x9900), ["PGP key public ring"], swap_endian=0 +signature file-magic-auto470 { + file-mime "application/x-pgp-keyring", 50 + file-magic /(\x99\x00)/ +} + +# >0 beshort&,=-27391 (0x9501), ["PGP key security ring"], swap_endian=0 +signature file-magic-auto471 { + file-mime "application/x-pgp-keyring", 50 + file-magic /(\x95\x01)/ +} + +# >0 beshort&,=-27392 (0x9500), ["PGP key security ring"], swap_endian=0 +signature file-magic-auto472 { + file-mime "application/x-pgp-keyring", 50 + file-magic /(\x95\x00)/ +} + +# >0 beshort&,=-23040 (0xa600), ["PGP encrypted data"], swap_endian=0 +signature file-magic-auto473 { + file-mime "text/PGP", 50 + file-magic /(\xa6\x00)/ +} + +# >0 string,=%! (len=2), ["PostScript document text"], swap_endian=0 +signature file-magic-auto474 { + file-mime "application/postscript", 50 + file-magic /(\x25\x21)/ +} + +# >0 search/1,=#! /usr/bin/env ruby (len=20), ["Ruby script text executable"], swap_endian=0 +signature file-magic-auto475 { + file-mime "text/x-ruby", 50 + file-magic /(.*)(\x23\x21 \x2fusr\x2fbin\x2fenv ruby)/ +} + +# >0 regex/1,=(^[0-9]{5})[acdn][w] (len=20), ["MARC21 Classification"], swap_endian=0 +signature file-magic-auto476 { + file-mime "application/marc", 50 + file-magic /((^[0-9]{5})[acdn][w])/ +} + +# >0 regex/1,=(^[0-9]{5})[acdn][w] (len=20), ["MARC21 Classification"], swap_endian=0 +# >>0 regex/1,=(^[0-9]{5})[cdn][q] (len=19), ["MARC21 Community"], swap_endian=0 +signature file-magic-auto477 { + file-mime "application/marc", 49 + file-magic /((^[0-9]{5})[acdn][w])((^[0-9]{5})[cdn][q])/ +} + +# >0 regex/1,=(^[0-9]{5})[acdn][w] (len=20), ["MARC21 Classification"], swap_endian=0 +# >>0 regex/1,=(^.{21})([^0]{2}) (len=17), ["(non-conforming)"], swap_endian=0 +signature file-magic-auto478 { + file-mime "application/marc", 47 + file-magic /((^[0-9]{5})[acdn][w])((^.{21})([^0]{2}))/ +} + +# >0 short&,=-14479 (0xc771), ["byte-swapped cpio archive"], swap_endian=0 +signature file-magic-auto479 { + file-mime "application/x-cpio", 50 + file-magic /((\x71\xc7)|(\xc7\x71))/ +} + +# >0 short&,=29127 (0x71c7), ["cpio archive"], swap_endian=0 +signature file-magic-auto480 { + file-mime "application/x-cpio", 50 + file-magic /((\xc7\x71)|(\x71\xc7))/ +} + +# >0 string,=\n( (len=2), ["Emacs v18 byte-compiled Lisp data"], swap_endian=0 +signature file-magic-auto481 { + file-mime "application/x-elc", 50 + file-magic /(\x0a\x28)/ +} + +# >0 string,=\021\t (len=2), ["Award BIOS Logo, 136 x 126"], swap_endian=0 +signature file-magic-auto482 { + file-mime "image/x-award-bioslogo", 50 + file-magic /(\x11\x09)/ +} + +# >0 string,=\021\006 (len=2), ["Award BIOS Logo, 136 x 84"], swap_endian=0 +signature file-magic-auto483 { + file-mime "image/x-award-bioslogo", 50 + file-magic /(\x11\x06)/ +} + +# >0 string,=P7 (len=2), ["Netpbm PAM image file"], swap_endian=0 +signature file-magic-auto484 { + file-mime "image/x-portable-pixmap", 50 + file-magic /(P7)/ +} + +# >0 beshort&ffffffffffffffe0,=22240 (0x56e0), ["MPEG-4 LOAS"], swap_endian=0 +signature file-magic-auto485 { + file-mime "audio/x-mp4a-latm", 50 + file-magic /(\x56[\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +} + +# >0 beshort&fffffffffffffff6,=-16 (0xfff0), ["MPEG ADTS, AAC"], swap_endian=0 +signature file-magic-auto486 { + file-mime "audio/x-hx-aac-adts", 50 + file-magic /(\xff[\xf0\xf1\xf8\xf9])/ +} + +# >0 beshort&fffffffffffffffe,=-30 (0xffe2), ["MPEG ADTS, layer III, v2.5"], swap_endian=0 +signature file-magic-auto487 { + file-mime "audio/mpeg", 50 + file-magic /(\xff[\xe2\xe3])/ +} + +# >0 beshort&fffffffffffffffe,=-10 (0xfff6), ["MPEG ADTS, layer I, v2"], swap_endian=0 +signature file-magic-auto488 { + file-mime "audio/mpeg", 50 + file-magic /(\xff[\xf6\xf7])/ +} + +# >0 beshort&fffffffffffffffe,=-14 (0xfff2), ["MPEG ADTS, layer III, v2"], swap_endian=0 +signature file-magic-auto489 { + file-mime "audio/mpeg", 50 + file-magic /(\xff[\xf2\xf3])/ +} + +# >0 beshort&fffffffffffffffe,=-4 (0xfffc), ["MPEG ADTS, layer II, v1"], swap_endian=0 +signature file-magic-auto490 { + file-mime "audio/mpeg", 50 + file-magic /(\xff[\xfc\xfd])/ +} + +# >0 search/1,=#! /usr/bin/env wish (len=20), ["Tcl/Tk script text executable"], swap_endian=0 +signature file-magic-auto491 { + file-mime "text/x-tcl", 50 + file-magic /(.*)(\x23\x21 \x2fusr\x2fbin\x2fenv wish)/ +} + +# >0 beshort&,=-26367 (0x9901), ["GPG key public ring"], swap_endian=0 +signature file-magic-auto492 { + file-mime "application/x-gnupg-keyring", 50 + file-magic /(\x99\x01)/ +} + +# >0 string,=\367\002 (len=2), ["TeX DVI file"], swap_endian=0 +signature file-magic-auto493 { + file-mime "application/x-dvi", 50 + file-magic /(\xf7\x02)/ +} + +# >2 string,=\000\021 (len=2), ["TeX font metric data"], swap_endian=0 +signature file-magic-auto494 { + file-mime "application/x-tex-tfm", 50 + file-magic /(.{2})(\x00\x11)/ +} + +# >2 string,=\000\022 (len=2), ["TeX font metric data"], swap_endian=0 +signature file-magic-auto495 { + file-mime "application/x-tex-tfm", 50 + file-magic /(.{2})(\x00\x12)/ +} + +# >0 beshort&,=-31486 (0x8502), ["GPG encrypted data"], swap_endian=0 +signature file-magic-auto496 { + file-mime "text/PGP", 50 + file-magic /(\x85\x02)/ +} + +# >4 string/W,=jP (len=2), ["JPEG 2000 image"], swap_endian=0 +signature file-magic-auto497 { + file-mime "image/jp2", 50 + file-magic /(.{4})(jP)/ +} + +# >0 regex,=^template[ \t\n]+ (len=15), ["C++ source text"], swap_endian=0 +signature file-magic-auto498 { + file-mime "text/x-c++", 50 + file-magic /(^template[ \x09\x0a]+)/ +} + +# >0 search/c/1,=0 string,=\037\235 (len=2), ["compress'd data"], swap_endian=0 +signature file-magic-auto500 { + file-mime "application/x-compress", 50 + file-magic /(\x1f\x9d)/ +} + +# >0 string,=\037\036 (len=2), ["packed data"], swap_endian=0 +signature file-magic-auto501 { + file-mime "application/octet-stream", 50 + file-magic /(\x1f\x1e)/ +} + +# >0 short&,=7967 (0x1f1f), ["old packed data"], swap_endian=0 +signature file-magic-auto502 { + file-mime "application/octet-stream", 50 + file-magic /((\x1f\x1f)|(\x1f\x1f))/ +} + +# >0 short&,=8191 (0x1fff), ["compacted data"], swap_endian=0 +signature file-magic-auto503 { + file-mime "application/octet-stream", 50 + file-magic /((\xff\x1f)|(\x1f\xff))/ +} + +# >0 string,=\377\037 (len=2), ["compacted data"], swap_endian=0 +signature file-magic-auto504 { + file-mime "application/octet-stream", 50 + file-magic /(\xff\x1f)/ +} + +# >0 short&,=-13563 (0xcb05), ["huf output"], swap_endian=0 +signature file-magic-auto505 { + file-mime "application/octet-stream", 50 + file-magic /((\x05\xcb)|(\xcb\x05))/ +} + +# >34 string,=LP (len=2), ["Embedded OpenType (EOT)"], swap_endian=0 +signature file-magic-auto506 { + file-mime "application/vnd.ms-fontobject", 50 + file-magic /(.{34})(LP)/ +} + +# >0 beshort&,=2935 (0x0b77), ["ATSC A/52 aka AC-3 aka Dolby Digital stream,"], swap_endian=0 +signature file-magic-auto507 { + file-mime "audio/vnd.dolby.dd-raw", 50 + file-magic /(\x0b\x77)/ +} + +# >0 search/1,=#!/usr/bin/env node (len=19), ["Node.js script text executable"], swap_endian=0 +signature file-magic-auto508 { + file-mime "application/javascript", 49 + file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fenv node)/ +} + +# >0 search/1,=#!/usr/bin/env wish (len=19), ["Tcl/Tk script text executable"], swap_endian=0 +signature file-magic-auto509 { + file-mime "text/x-tcl", 49 + file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fenv wish)/ +} + +# >0 regex,=^[ \t]{0,50}\.asciiz (len=19), ["assembler source text"], swap_endian=0 +signature file-magic-auto510 { + file-mime "text/x-asm", 49 + file-magic /(^[ \x09]{0,50}\.asciiz)/ +} + +# >0 search/1,=#!/usr/bin/env perl (len=19), ["Perl script text executable"], swap_endian=0 +signature file-magic-auto511 { + file-mime "text/x-perl", 49 + file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fenv perl)/ +} + +# >0 search/Wct/4096,=0 regex,=^virtual[ \t\n]+ (len=14), ["C++ source text"], swap_endian=0 +signature file-magic-auto513 { + file-mime "text/x-c++", 49 + file-magic /(^virtual[ \x09\x0a]+)/ +} + +# >0 search/1,=#! /usr/bin/env lua (len=19), ["Lua script text executable"], swap_endian=0 +signature file-magic-auto514 { + file-mime "text/x-lua", 49 + file-magic /(.*)(\x23\x21 \x2fusr\x2fbin\x2fenv lua)/ +} + +# >0 search/1,=#!/usr/bin/env ruby (len=19), ["Ruby script text executable"], swap_endian=0 +signature file-magic-auto515 { + file-mime "text/x-ruby", 49 + file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fenv ruby)/ +} + +# >0 search/1,=#! /usr/bin/env tcl (len=19), ["Tcl script text executable"], swap_endian=0 +signature file-magic-auto516 { + file-mime "text/x-tcl", 49 + file-magic /(.*)(\x23\x21 \x2fusr\x2fbin\x2fenv tcl)/ +} + +# >0 regex,=^[ \t]{0,50}\.globl (len=18), ["assembler source text"], swap_endian=0 +signature file-magic-auto517 { + file-mime "text/x-asm", 48 + file-magic /(^[ \x09]{0,50}\.globl)/ +} + +# >0 search/1,=#!/usr/bin/env tcl (len=18), ["Tcl script text executable"], swap_endian=0 +signature file-magic-auto518 { + file-mime "text/x-tcl", 48 + file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fenv tcl)/ +} + +# >0 search/1,=#!/usr/bin/env lua (len=18), ["Lua script text executable"], swap_endian=0 +signature file-magic-auto519 { + file-mime "text/x-lua", 48 + file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fenv lua)/ +} + +# >0 search/w/1,=#! /usr/bin/python (len=18), ["Python script text executable"], swap_endian=0 +signature file-magic-auto520 { + file-mime "text/x-python", 48 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2fbin\x2fpython)/ +} + +# >0 search/w/1,=#!/usr/bin/nodejs (len=17), ["Node.js script text executable"], swap_endian=0 +signature file-magic-auto521 { + file-mime "application/javascript", 47 + file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fnodejs)/ +} + +# >0 regex,=^class[ \t\n]+ (len=12), ["C++ source text"], swap_endian=0 +signature file-magic-auto522 { + file-mime "text/x-c++", 47 + file-magic /(^class[ \x09\x0a]+)/ +} + +# >0 regex,=^[ \t]{0,50}\.text (len=17), ["assembler source text"], swap_endian=0 +signature file-magic-auto523 { + file-mime "text/x-asm", 47 + file-magic /(^[ \x09]{0,50}\.text)/ +} + +# >0 regex,=^[ \t]{0,50}\.even (len=17), ["assembler source text"], swap_endian=0 +signature file-magic-auto524 { + file-mime "text/x-asm", 47 + file-magic /(^[ \x09]{0,50}\.even)/ +} + +# >0 regex,=^[ \t]{0,50}\.byte (len=17), ["assembler source text"], swap_endian=0 +signature file-magic-auto525 { + file-mime "text/x-asm", 47 + file-magic /(^[ \x09]{0,50}\.byte)/ +} + +# >0 regex,=^[ \t]{0,50}\.file (len=17), ["assembler source text"], swap_endian=0 +signature file-magic-auto526 { + file-mime "text/x-asm", 47 + file-magic /(^[ \x09]{0,50}\.file)/ +} + +# >0 regex,=^[ \t]{0,50}\.type (len=17), ["assembler source text"], swap_endian=0 +signature file-magic-auto527 { + file-mime "text/x-asm", 47 + file-magic /(^[ \x09]{0,50}\.type)/ +} + +# >0 search/1,=This is Info file (len=17), ["GNU Info text"], swap_endian=0 +signature file-magic-auto528 { + file-mime "text/x-info", 47 + file-magic /(.*)(This is Info file)/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 regex/c,=^(autorun)]\r\n (len=13), [""], swap_endian=0 +# >>>>&0 ubyte&,=0x5b, ["INItialization configuration"], swap_endian=0 +signature file-magic-auto529 { + file-mime "application/x-wine-extension-ini", 40 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(^([aA][uU][tT][oO][rR][uU][nN])]\x0d\x0a)([\x5b])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 regex/c,=^(autorun)]\r\n (len=13), [""], swap_endian=0 +# >>>>&0 ubyte&,!0x5b, ["Microsoft Windows Autorun file"], swap_endian=0 +signature file-magic-auto530 { + file-mime "application/x-setupscript", 1 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(^([aA][uU][tT][oO][rR][uU][nN])]\x0d\x0a)([\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 regex/c,=^(version|strings)] (len=19), ["Windows setup INFormation"], swap_endian=0 +signature file-magic-auto531 { + file-mime "application/x-setupscript", 49 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(^([vV][eE][rR][sS][iI][oO][nN]|[sS][tT][rR][iI][nN][gG][sS])])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 regex/c,=^(WinsockCRCList|OEMCPL)] (len=25), ["Windows setup INFormation"], swap_endian=0 +signature file-magic-auto532 { + file-mime "text/inf", 55 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(^([Ww][iI][nN][sS][oO][cC][kK][Cc][Rr][Cc][Ll][iI][sS][tT]|[Oo][Ee][Mm][Cc][Pp][Ll])])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 regex/c,=^(.ShellClassInfo|DeleteOnCopy|LocalizedFileNames)] (len=51), ["Windows desktop.ini"], swap_endian=0 +signature file-magic-auto533 { + file-mime "application/x-wine-extension-ini", 81 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(^(.[Ss][hH][eE][lL][lL][Cc][lL][aA][sS][sS][Ii][nN][fF][oO]|[Dd][eE][lL][eE][tT][eE][Oo][nN][Cc][oO][pP][yY]|[Ll][oO][cC][aA][lL][iI][zZ][eE][dD][Ff][iI][lL][eE][Nn][aA][mM][eE][sS])])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 regex/c,=^(don't load)] (len=14), ["Windows CONTROL.INI"], swap_endian=0 +signature file-magic-auto534 { + file-mime "application/x-wine-extension-ini", 44 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(^([dD][oO][nN]'[tT] [lL][oO][aA][dD])])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 regex/c,=^(ndishlp\$|protman\$|NETBEUI\$)] (len=33), ["Windows PROTOCOL.INI"], swap_endian=0 +signature file-magic-auto535 { + file-mime "application/x-wine-extension-ini", 63 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(^([nN][dD][iI][sS][hH][lL][pP]\$|[pP][rR][oO][tT][mM][aA][nN]\$|[Nn][Ee][Tt][Bb][Ee][Uu][Ii]\$)])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 regex/c,=^(windows|Compatibility|embedding)] (len=35), ["Windows WIN.INI"], swap_endian=0 +signature file-magic-auto536 { + file-mime "application/x-wine-extension-ini", 65 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(^([wW][iI][nN][dD][oO][wW][sS]|[Cc][oO][mM][pP][aA][tT][iI][bB][iI][lL][iI][tT][yY]|[eE][mM][bB][eE][dD][dD][iI][nN][gG])])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 regex/c,=^(boot|386enh|drivers)] (len=23), ["Windows SYSTEM.INI"], swap_endian=0 +signature file-magic-auto537 { + file-mime "application/x-wine-extension-ini", 53 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(^([bB][oO][oO][tT]|386[eE][nN][hH]|[dD][rR][iI][vV][eE][rR][sS])])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 regex/c,=^(SafeList)] (len=12), ["Windows IOS.INI"], swap_endian=0 +signature file-magic-auto538 { + file-mime "application/x-wine-extension-ini", 42 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(^([Ss][aA][fF][eE][Ll][iI][sS][tT])])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 regex/c,=^(boot loader)] (len=15), ["Windows boot.ini"], swap_endian=0 +signature file-magic-auto539 { + file-mime "application/x-wine-extension-ini", 45 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(^([bB][oO][oO][tT] [lL][oO][aA][dD][eE][rR])])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 ubequad&ffdfffdfffdfffdf,=24207144355233875 (0x0056004500520053), [""], swap_endian=0 +# >>>>&0 ubequad&ffdfffdfffdfffff,=20548012607406173 (0x0049004f004e005d), ["Windows setup INFormation "], swap_endian=0 +signature file-magic-auto540 { + file-mime "application/x-setupscript", 110 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(\x00[\x56\x76]\x00[\x45\x65]\x00[\x52\x72]\x00[\x53\x73])(\x00[\x49\x69]\x00[\x4f\x6f]\x00[\x4e\x6e]\x00\x5d)/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 ubequad&ffdfffdfffdfffdf,=23362783849611337 (0x0053005400520049), [""], swap_endian=0 +# >>>>&0 ubequad&ffdfffdfffdfffff,=21955353131548765 (0x004e00470053005d), ["Windows setup INFormation "], swap_endian=0 +signature file-magic-auto541 { + file-mime "application/x-setupscript", 110 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(\x00[\x53\x73]\x00[\x54\x74]\x00[\x52\x72]\x00[\x49\x69)(\x00[\x4e\x6e]\x00[\x47\x67]\x00[\x53\x73]\x00\x5d)/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 default&,x, [""], swap_endian=0 +# >>>>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>>>&0 string/c,=version (len=7), ["Windows setup INFormation "], swap_endian=0 +signature file-magic-auto542 { + file-mime "application/x-setupscript", 100 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(.*)(\x5b)([vV][eE][rR][sS][iI][oO][nN])/ +} + +# >0 regex/s,=\`(\r\n|;|[[]|\377\376) (len=15), [""], swap_endian=0 +# >>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>&0 default&,x, [""], swap_endian=0 +# >>>>&0 search/8192,=[ (len=1), [""], swap_endian=0 +# >>>>>&0 ubequad&ffdfffdfffdfffdf,=24207144355233875 (0x0056004500520053), [""], swap_endian=0 +# >>>>>>&0 ubequad&ffdfffdfffdfffff,=20548012607406173 (0x0049004f004e005d), ["Windows setup INFormation "], swap_endian=0 +signature file-magic-auto543 { + file-mime "application/x-setupscript", 110 + file-magic /(\`(\x0d\x0a|;|[[]|\xff\xfe))(.*)(\x5b)(.*)(\x5b)(\x00[\x56\x76]\x00[\x45\x65]\x00[\x52\x72]\x00[\x53\x73])(\x00[\x49\x69]\x00[\x4f\x6f]\x00[\x4e\x6e]\x00\x5d)/ +} + +# >0 search/1,=0 search/w/1,=#! /usr/bin/wish (len=16), ["Tcl/Tk script text executable"], swap_endian=0 +signature file-magic-auto545 { + file-mime "text/x-tcl", 46 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2fbin\x2fwish)/ +} + +# >0 search/w/1,=#! /usr/bin/ruby (len=16), ["Ruby script text executable"], swap_endian=0 +signature file-magic-auto546 { + file-mime "text/x-ruby", 46 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2fbin\x2fruby)/ +} + +# >0 search/w/1,=#! /usr/bin/lua (len=15), ["Lua script text executable"], swap_endian=0 +signature file-magic-auto547 { + file-mime "text/x-lua", 45 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2fbin\x2flua)/ +} + +# >0 search/w/1,=#! /usr/bin/tcl (len=15), ["Tcl script text executable"], swap_endian=0 +signature file-magic-auto548 { + file-mime "text/x-tcl", 45 + file-magic /(.*)(\x23\x21 ?\x2fusr\x2fbin\x2ftcl)/ +} + +# >0 search/wct/4096,=0 search/wct/4096,=0 search/w/1,=#!/usr/bin/node (len=15), ["Node.js script text executable"], swap_endian=0 +signature file-magic-auto551 { + file-mime "application/javascript", 45 + file-magic /(.*)(\x23\x21\x2fusr\x2fbin\x2fnode)/ +} + +# >0 search/wct/1,=0 search/1,=\input texinfo (len=14), ["Texinfo source text"], swap_endian=0 +signature file-magic-auto553 { + file-mime "text/x-texinfo", 44 + file-magic /(.*)(\x5cinput texinfo)/ +} + +# >0 regex,=^private: (len=9), ["C++ source text"], swap_endian=0 +signature file-magic-auto554 { + file-mime "text/x-c++", 44 + file-magic /(^private:)/ +} + +# >0 search/4096,=def __init__ (len=12), [""], swap_endian=0 +# >>&0 search/64,=self (len=4), ["Python script text executable"], swap_endian=0 +signature file-magic-auto555 { + file-mime "text/x-python", 38 + file-magic /(.*)(def \x5f\x5finit\x5f\x5f)(.*)(self)/ +} + +# >0 search/wct/4096,=0 regex,=^extern[ \t\n]+ (len=13), ["C source text"], swap_endian=0 +signature file-magic-auto557 { + file-mime "text/x-c", 43 + file-magic /(^extern[ \x09\x0a]+)/ +} + +# >0 search/4096,=% -*-latex-*- (len=13), ["LaTeX document text"], swap_endian=0 +signature file-magic-auto558 { + file-mime "text/x-tex", 43 + file-magic /(.*)(\x25 \x2d\x2a\x2dlatex\x2d\x2a\x2d)/ +} + +# >0 regex,=^double[ \t\n]+ (len=13), ["C source text"], swap_endian=0 +signature file-magic-auto559 { + file-mime "text/x-c", 43 + file-magic /(^double[ \x09\x0a]+)/ +} + +# >0 regex,=^struct[ \t\n]+ (len=13), ["C source text"], swap_endian=0 +signature file-magic-auto560 { + file-mime "text/x-c", 43 + file-magic /(^struct[ \x09\x0a]+)/ +} + +# >0 search/w/1,=#!/bin/nodejs (len=13), ["Node.js script text executable"], swap_endian=0 +signature file-magic-auto561 { + file-mime "application/javascript", 43 + file-magic /(.*)(\x23\x21\x2fbin\x2fnodejs)/ +} + +# >0 regex,=^public: (len=8), ["C++ source text"], swap_endian=0 +signature file-magic-auto562 { + file-mime "text/x-c++", 43 + file-magic /(^public:)/ +} + +# >0 search/wct/4096,=