diff --git a/src/Makefile.am b/src/Makefile.am index b941a09e91..6c2744829d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -344,6 +344,7 @@ util-decode-asn1.c util-decode-asn1.h \ util-decode-der.c util-decode-der.h \ util-decode-der-get.c util-decode-der-get.h \ util-decode-mime.c util-decode-mime.h \ +util-detect-file-hash.c util-detect-file-hash.h \ util-device.c util-device.h \ util-enum.c util-enum.h \ util-error.c util-error.h \ diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index 18c4661639..6d8be5394e 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -23,37 +23,14 @@ */ #include "suricata-common.h" -#include "threads.h" -#include "debug.h" -#include "decode.h" -#include "detect.h" -#include "detect-parse.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-print.h" +#include "util-detect-file-hash.h" #include "util-unittest.h" #include "util-unittest-helper.h" -#include "app-layer.h" - -#include "stream-tcp.h" - #include "detect-filemd5.h" -#include "queue.h" -#include "util-rohash.h" - #ifndef HAVE_NSS static int DetectFileMd5SetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) @@ -74,17 +51,14 @@ void DetectFileMd5Register(void) sigmatch_table[DETECT_FILEMD5].RegisterTests = NULL; sigmatch_table[DETECT_FILEMD5].flags = SIGMATCH_NOT_BUILT; - SCLogDebug("registering filemd5 rule option"); + SCLogDebug("registering filemd5 rule option"); return; } #else /* HAVE_NSS */ -static int DetectFileMd5Match (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, File *, Signature *, SigMatch *); static int DetectFileMd5Setup (DetectEngineCtx *, Signature *, char *); static void DetectFileMd5RegisterTests(void); -static void DetectFileMd5Free(void *); /** * \brief Registration function for keyword: filemd5 @@ -94,203 +68,15 @@ void DetectFileMd5Register(void) sigmatch_table[DETECT_FILEMD5].name = "filemd5"; sigmatch_table[DETECT_FILEMD5].desc = "match file MD5 against list of MD5 checksums"; sigmatch_table[DETECT_FILEMD5].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemd5"; - sigmatch_table[DETECT_FILEMD5].FileMatch = DetectFileMd5Match; + sigmatch_table[DETECT_FILEMD5].FileMatch = DetectFileHashMatch; sigmatch_table[DETECT_FILEMD5].Setup = DetectFileMd5Setup; - sigmatch_table[DETECT_FILEMD5].Free = DetectFileMd5Free; + sigmatch_table[DETECT_FILEMD5].Free = DetectFileHashFree; sigmatch_table[DETECT_FILEMD5].RegisterTests = DetectFileMd5RegisterTests; - SCLogDebug("registering filemd5 rule option"); + SCLogDebug("registering filemd5 rule option"); return; } -static int Md5ReadString(uint8_t *md5, char *str, char *filename, int line_no) -{ - if (strlen(str) != 32) { - SCLogError(SC_ERR_INVALID_MD5, "%s:%d md5 string not 32 bytes", - filename, line_no); - return -1; - } - - int i, x; - for (x = 0, i = 0; i < 32; i+=2, x++) { - char buf[3] = { 0, 0, 0}; - buf[0] = str[i]; - buf[1] = str[i+1]; - - long value = strtol(buf, NULL, 16); - if (value >= 0 && value <= 255) - md5[x] = (uint8_t)value; - else { - SCLogError(SC_ERR_INVALID_MD5, "%s:%d md5 byte out of range %ld", - filename, line_no, value); - return -1; - } - } - - return 1; -} - -static int MD5LoadHash(ROHashTable *hash, char *string, char *filename, int line_no) -{ - uint8_t md5[16]; - - if (Md5ReadString(md5, string, filename, line_no) == 1) { - if (ROHashInitQueueValue(hash, &md5, (uint16_t)sizeof(md5)) != 1) - return -1; - } - - return 1; -} - -static int MD5MatchLookupBuffer(ROHashTable *hash, uint8_t *buf, size_t buflen) -{ - void *ptr = ROHashLookup(hash, buf, (uint16_t)buflen); - if (ptr == NULL) - return 0; - else - return 1; -} - -/** - * \brief match the specified filemd5 - * - * \param t thread local vars - * \param det_ctx pattern matcher thread local data - * \param f *LOCKED* flow - * \param flags direction flags - * \param file file being inspected - * \param s signature being inspected - * \param m sigmatch that we will cast into DetectFileMd5Data - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectFileMd5Match (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) -{ - SCEnter(); - int ret = 0; - DetectFileMd5Data *filemd5 = (DetectFileMd5Data *)m->ctx; - - if (file->txid < det_ctx->tx_id) { - SCReturnInt(0); - } - - if (file->txid > det_ctx->tx_id) { - SCReturnInt(0); - } - - if (file->state != FILE_STATE_CLOSED) { - SCReturnInt(0); - } - - if (file->flags & FILE_MD5) { - if (MD5MatchLookupBuffer(filemd5->hash, file->md5, sizeof(file->md5)) == 1) { - if (filemd5->negated == 0) - ret = 1; - else - ret = 0; - } else { - if (filemd5->negated == 0) - ret = 0; - else - ret = 1; - } - } - - SCReturnInt(ret); -} - -/** - * \brief Parse the filemd5 keyword - * - * \param idstr Pointer to the user provided option - * - * \retval filemd5 pointer to DetectFileMd5Data on success - * \retval NULL on failure - */ -static DetectFileMd5Data *DetectFileMd5Parse (const DetectEngineCtx *de_ctx, char *str) -{ - DetectFileMd5Data *filemd5 = NULL; - FILE *fp = NULL; - char *filename = NULL; - - /* We have a correct filemd5 option */ - filemd5 = SCMalloc(sizeof(DetectFileMd5Data)); - if (unlikely(filemd5 == NULL)) - goto error; - - memset(filemd5, 0x00, sizeof(DetectFileMd5Data)); - - if (strlen(str) && str[0] == '!') { - filemd5->negated = 1; - str++; - } - - filemd5->hash = ROHashInit(18, 16); - if (filemd5->hash == NULL) { - goto error; - } - - /* get full filename */ - filename = DetectLoadCompleteSigPath(de_ctx, str); - if (filename == NULL) { - goto error; - } - - char line[8192] = ""; - fp = fopen(filename, "r"); - if (fp == NULL) { - SCLogError(SC_ERR_OPENING_RULE_FILE, "opening md5 file %s: %s", filename, strerror(errno)); - goto error; - } - - int line_no = 0; - while(fgets(line, (int)sizeof(line), fp) != NULL) { - size_t len = strlen(line); - line_no++; - - /* ignore comments and empty lines */ - if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') - continue; - - while (isspace(line[--len])); - - /* Check if we have a trailing newline, and remove it */ - len = strlen(line); - if (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) { - line[len - 1] = '\0'; - } - - /* cut off longer lines */ - if (strlen(line) > 32) - line[32] = 0x00; - - if (MD5LoadHash(filemd5->hash, line, filename, line_no) != 1) { - goto error; - } - } - fclose(fp); - fp = NULL; - - if (ROHashInitFinalize(filemd5->hash) != 1) { - goto error; - } - SCLogInfo("MD5 hash size %u bytes%s", ROHashMemorySize(filemd5->hash), filemd5->negated ? ", negated match" : ""); - - SCFree(filename); - return filemd5; - -error: - if (filemd5 != NULL) - DetectFileMd5Free(filemd5); - if (fp != NULL) - fclose(fp); - if (filename != NULL) - SCFree(filename); - return NULL; -} - /** * \brief this function is used to parse filemd5 options * \brief into the current signature @@ -304,55 +90,14 @@ error: */ static int DetectFileMd5Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) { - DetectFileMd5Data *filemd5 = NULL; - SigMatch *sm = NULL; - - filemd5 = DetectFileMd5Parse(de_ctx, str); - if (filemd5 == NULL) - goto error; - - /* Okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - sm = SigMatchAlloc(); - if (sm == NULL) - goto error; - - sm->type = DETECT_FILEMD5; - sm->ctx = (void *)filemd5; - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - - s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MD5); - return 0; - -error: - if (filemd5 != NULL) - DetectFileMd5Free(filemd5); - if (sm != NULL) - SCFree(sm); - return -1; -} - -/** - * \brief this function will free memory associated with DetectFileMd5Data - * - * \param filemd5 pointer to DetectFileMd5Data - */ -static void DetectFileMd5Free(void *ptr) -{ - if (ptr != NULL) { - DetectFileMd5Data *filemd5 = (DetectFileMd5Data *)ptr; - if (filemd5->hash != NULL) - ROHashFree(filemd5->hash); - SCFree(filemd5); - } + return DetectFileHashSetup(de_ctx, s, str, DETECT_FILEMD5); } #ifdef UNITTESTS static int MD5MatchLookupString(ROHashTable *hash, char *string) { uint8_t md5[16]; - if (Md5ReadString(md5, string, "file", 88) == 1) { + if (ReadHashString(md5, string, "file", 88, 32) == 1) { void *ptr = ROHashLookup(hash, &md5, (uint16_t)sizeof(md5)); if (ptr == NULL) return 0; @@ -368,17 +113,17 @@ static int MD5MatchTest01(void) if (hash == NULL) { return 0; } - if (MD5LoadHash(hash, "d80f93a93dc5f3ee945704754d6e0a36", "file", 1) != 1) + if (LoadHashTable(hash, "d80f93a93dc5f3ee945704754d6e0a36", "file", 1, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "92a49985b384f0d993a36e4c2d45e206", "file", 2) != 1) + if (LoadHashTable(hash, "92a49985b384f0d993a36e4c2d45e206", "file", 2, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "11adeaacc8c309815f7bc3e33888f281", "file", 3) != 1) + if (LoadHashTable(hash, "11adeaacc8c309815f7bc3e33888f281", "file", 3, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "22e10a8fe02344ade0bea8836a1714af", "file", 4) != 1) + if (LoadHashTable(hash, "22e10a8fe02344ade0bea8836a1714af", "file", 4, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "c3db2cbf02c68f073afcaee5634677bc", "file", 5) != 1) + if (LoadHashTable(hash, "c3db2cbf02c68f073afcaee5634677bc", "file", 5, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "7ed095da259638f42402fb9e74287a17", "file", 6) != 1) + if (LoadHashTable(hash, "7ed095da259638f42402fb9e74287a17", "file", 6, DETECT_FILEMD5) != 1) return 0; if (ROHashInitFinalize(hash) != 1) { @@ -397,7 +142,7 @@ static int MD5MatchTest01(void) return 0; if (MD5MatchLookupString(hash, "7ed095da259638f42402fb9e74287a17") != 1) return 0; - /* shouldnt match */ + /* shouldn't match */ if (MD5MatchLookupString(hash, "33333333333333333333333333333333") == 1) return 0; diff --git a/src/detect-filemd5.h b/src/detect-filemd5.h index 486812f7c6..0905fc4ce0 100644 --- a/src/detect-filemd5.h +++ b/src/detect-filemd5.h @@ -24,13 +24,6 @@ #ifndef __DETECT_FILEMD5_H__ #define __DETECT_FILEMD5_H__ -#include "util-rohash.h" - -typedef struct DetectFileMd5Data { - ROHashTable *hash; - int negated; -} DetectFileMd5Data; - /* prototypes */ void DetectFileMd5Register (void); diff --git a/src/detect.h b/src/detect.h index d5562ba534..3031f4d4c6 100644 --- a/src/detect.h +++ b/src/detect.h @@ -305,11 +305,12 @@ typedef struct DetectPort_ { #define FILE_SIG_NEED_FILE 0x01 #define FILE_SIG_NEED_FILENAME 0x02 -#define FILE_SIG_NEED_TYPE 0x04 -#define FILE_SIG_NEED_MAGIC 0x08 /**< need the start of the file */ -#define FILE_SIG_NEED_FILECONTENT 0x10 -#define FILE_SIG_NEED_MD5 0x20 -#define FILE_SIG_NEED_SIZE 0x40 +#define FILE_SIG_NEED_MAGIC 0x04 /**< need the start of the file */ +#define FILE_SIG_NEED_FILECONTENT 0x08 +#define FILE_SIG_NEED_MD5 0x10 +#define FILE_SIG_NEED_SHA1 0x20 +#define FILE_SIG_NEED_SHA256 0x40 +#define FILE_SIG_NEED_SIZE 0x80 /* Detection Engine flags */ #define DE_QUIET 0x01 /**< DE is quiet (esp for unittests) */ @@ -1216,6 +1217,8 @@ enum { DETECT_FILESTORE, DETECT_FILEMAGIC, DETECT_FILEMD5, + DETECT_FILESHA1, + DETECT_FILESHA256, DETECT_FILESIZE, DETECT_L3PROTO, diff --git a/src/util-detect-file-hash.c b/src/util-detect-file-hash.c new file mode 100644 index 0000000000..49b93eb8f7 --- /dev/null +++ b/src/util-detect-file-hash.c @@ -0,0 +1,368 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Duarte Silva + * + */ + +#include "suricata-common.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "util-detect-file-hash.h" + +#include "app-layer-htp.h" + +#ifdef HAVE_NSS + +/** + * \brief Read the bytes of a hash from an hexadecimal string + * + * \param hash buffer to store the resulting bytes + * \param string hexadecimal string representing the hash + * \param filename file name from where the string was read + * \param line_no file line number from where the string was read + * \param expected_len the expected length of the string that was read + * + * \retval -1 the hexadecimal string is invalid + * \retval 1 the hexadecimal string was read successfully + */ +int ReadHashString(uint8_t *hash, char *string, char *filename, int line_no, + uint16_t expected_len) +{ + if (strlen(string) != expected_len) { + SCLogError(SC_ERR_INVALID_HASH, "%s:%d hash string not %d characters", + filename, line_no, expected_len); + return -1; + } + + int i, x; + for (x = 0, i = 0; i < expected_len; i+=2, x++) { + char buf[3] = { 0, 0, 0 }; + buf[0] = string[i]; + buf[1] = string[i+1]; + + long value = strtol(buf, NULL, 16); + if (value >= 0 && value <= 255) + hash[x] = (uint8_t)value; + else { + SCLogError(SC_ERR_INVALID_HASH, "%s:%d hash byte out of range %ld", + filename, line_no, value); + return -1; + } + } + + return 1; +} + +/** + * \brief Store a hash into the hash table + * + * \param hash_table hash table that will hold the hash + * \param string hexadecimal string representing the hash + * \param filename file name from where the string was read + * \param line_no file line number from where the string was read + * \param type the hash algorithm + * + * \retval -1 failed to load the hash into the hash table + * \retval 1 successfully loaded the has into the hash table + */ +int LoadHashTable(ROHashTable *hash_table, char *string, char *filename, + int line_no, uint32_t type) +{ + /* allocate the maximum size a hash can have (in this case is SHA256, 32 bytes) */ + uint8_t hash[32]; + /* specify the actual size that should be read depending on the hash algorithm */ + uint16_t size = 32; + + if (type == DETECT_FILEMD5) { + size = 16; + } + else if (type == DETECT_FILESHA1) { + size = 20; + } + + /* every byte represented with hexadecimal digits is two characters */ + uint16_t expected_len = (size * 2); + + if (ReadHashString(hash, string, filename, line_no, expected_len) == 1) { + if (ROHashInitQueueValue(hash_table, &hash, size) != 1) + return -1; + } + + return 1; +} + +/** + * \brief Match a hash stored in a hash table + * + * \param hash_table hash table that will hold the hash + * \param hash buffer containing the bytes of the has + * \param hash_len length of the hash buffer + * + * \retval 0 didn't find the specified hash + * \retval 1 the hash matched a stored value + */ +static int HashMatchHashTable(ROHashTable *hash_table, uint8_t *hash, + size_t hash_len) +{ + void *ptr = ROHashLookup(hash_table, hash, (uint16_t)hash_len); + if (ptr == NULL) + return 0; + else + return 1; +} + +/** + * \brief Match the specified file hash + * + * \param t thread local vars + * \param det_ctx pattern matcher thread local data + * \param f *LOCKED* flow + * \param flags direction flags + * \param file file being inspected + * \param s signature being inspected + * \param m sigmatch that we will cast into DetectFileHashData + * + * \retval 0 no match + * \retval 1 match + */ +int DetectFileHashMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) +{ + SCEnter(); + int ret = 0; + DetectFileHashData *filehash = (DetectFileHashData *)m->ctx; + + if (file->txid < det_ctx->tx_id) { + SCReturnInt(0); + } + + if (file->txid > det_ctx->tx_id) { + SCReturnInt(0); + } + + if (file->state != FILE_STATE_CLOSED) { + SCReturnInt(0); + } + + int match = -1; + + if (s->file_flags & FILE_SIG_NEED_MD5 && file->flags & FILE_MD5) { + match = HashMatchHashTable(filehash->hash, file->md5, sizeof(file->md5)); + } + else if (s->file_flags & FILE_SIG_NEED_SHA1 && file->flags & FILE_SHA1) { + match = HashMatchHashTable(filehash->hash, file->sha1, sizeof(file->sha1)); + } + else if (s->file_flags & FILE_SIG_NEED_SHA256 && file->flags & FILE_SHA256) { + match = HashMatchHashTable(filehash->hash, file->sha256, sizeof(file->sha256)); + } + + if (match == 1) { + if (filehash->negated == 0) + ret = 1; + else + ret = 0; + } + else if (match == 0) { + if (filehash->negated == 0) + ret = 0; + else + ret = 1; + } + + SCReturnInt(ret); +} + +/** + * \brief Parse the filemd5 keyword + * + * \param det_ctx pattern matcher thread local data + * \param str Pointer to the user provided option + * \param type the hash algorithm + * + * \retval filemd5 pointer to DetectFileHashData on success + * \retval NULL on failure + */ +static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, + char *str, uint32_t type) +{ + DetectFileHashData *filehash = NULL; + FILE *fp = NULL; + char *filename = NULL; + + /* We have a correct filemd5 option */ + filehash = SCMalloc(sizeof(DetectFileHashData)); + if (unlikely(filehash == NULL)) + goto error; + + memset(filehash, 0x00, sizeof(DetectFileHashData)); + + if (strlen(str) && str[0] == '!') { + filehash->negated = 1; + str++; + } + + if (type == DETECT_FILEMD5) { + filehash->hash = ROHashInit(18, 16); + } + else if (type == DETECT_FILESHA1) { + filehash->hash = ROHashInit(18, 20); + } + else if (type == DETECT_FILESHA256) { + filehash->hash = ROHashInit(18, 32); + } + + if (filehash->hash == NULL) { + goto error; + } + + /* get full filename */ + filename = DetectLoadCompleteSigPath(de_ctx, str); + if (filename == NULL) { + goto error; + } + + char line[8192] = ""; + fp = fopen(filename, "r"); + if (fp == NULL) { + SCLogError(SC_ERR_OPENING_RULE_FILE, "opening hash file %s: %s", filename, strerror(errno)); + goto error; + } + + int line_no = 0; + while(fgets(line, (int)sizeof(line), fp) != NULL) { + size_t len = strlen(line); + line_no++; + + /* ignore comments and empty lines */ + if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') + continue; + + while (isspace(line[--len])); + + /* Check if we have a trailing newline, and remove it */ + len = strlen(line); + if (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) { + line[len - 1] = '\0'; + } + + /* cut off longer lines than a SHA256 represented in hexadecimal */ + if (strlen(line) > 64) + line[64] = 0x00; + + if (LoadHashTable(filehash->hash, line, filename, line_no, type) != 1) { + goto error; + } + } + fclose(fp); + fp = NULL; + + if (ROHashInitFinalize(filehash->hash) != 1) { + goto error; + } + SCLogInfo("Hash hash table size %u bytes%s", ROHashMemorySize(filehash->hash), filehash->negated ? ", negated match" : ""); + + SCFree(filename); + return filehash; + +error: + if (filehash != NULL) + DetectFileHashFree(filehash); + if (fp != NULL) + fclose(fp); + if (filename != NULL) + SCFree(filename); + return NULL; +} + +/** + * \brief this function is used to parse filemd5, filesha1 and filesha256 options + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided "filemd5", "filesha1" or "filesha256" option + * \param type type of file hash to setup + * + * \retval 0 on Success + * \retval -1 on Failure + */ +int DetectFileHashSetup (DetectEngineCtx *de_ctx, Signature *s, char *str, + uint32_t type) +{ + DetectFileHashData *filehash = NULL; + SigMatch *sm = NULL; + + filehash = DetectFileHashParse(de_ctx, str, type); + if (filehash == NULL) + goto error; + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = type; + sm->ctx = (void *)filehash; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); + + s->file_flags |= FILE_SIG_NEED_FILE; + + // Setup the file flags depending on the hashing algorithm + if (type == DETECT_FILEMD5) { + s->file_flags |= FILE_SIG_NEED_MD5; + } + if (type == DETECT_FILESHA1) { + s->file_flags |= FILE_SIG_NEED_SHA1; + } + if (type == DETECT_FILESHA256) { + s->file_flags |= FILE_SIG_NEED_SHA256; + } + return 0; + +error: + if (filehash != NULL) + DetectFileHashFree(filehash); + if (sm != NULL) + SCFree(sm); + return -1; +} + +/** + * \brief this function will free memory associated with DetectFileHashData + * + * \param filehash pointer to DetectFileHashData + */ +void DetectFileHashFree(void *ptr) +{ + if (ptr != NULL) { + DetectFileHashData *filehash = (DetectFileHashData *)ptr; + if (filehash->hash != NULL) + ROHashFree(filehash->hash); + SCFree(filehash); + } +} + +#endif /* HAVE_NSS */ diff --git a/src/util-detect-file-hash.h b/src/util-detect-file-hash.h new file mode 100644 index 0000000000..19d5418c3e --- /dev/null +++ b/src/util-detect-file-hash.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Duarte Silva + * + */ + +#ifndef __UTIL_DETECT_FILE_HASH_H__ +#define __UTIL_DETECT_FILE_HASH_H__ + +#include "util-rohash.h" + +typedef struct DetectFileHashData { + ROHashTable *hash; + int negated; +} DetectFileHashData; + +/* prototypes */ +int ReadHashString(uint8_t *, char *, char *, int, uint16_t); +int LoadHashTable(ROHashTable *, char *, char *, int, uint32_t); + +int DetectFileHashMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, + File *, Signature *, SigMatch *); +int DetectFileHashSetup(DetectEngineCtx *, Signature *, char *, uint32_t); +void DetectFileHashFree(void *); + +#endif /* __UTIL_DETECT_FILE_HASH_H__ */ diff --git a/src/util-error.c b/src/util-error.c index 50d013c58c..94d3e02d05 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -326,6 +326,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_SSH_LOG_GENERIC); CASE_CODE (SC_ERR_NIC_OFFLOADING); CASE_CODE (SC_ERR_NO_FILES_FOR_PROTOCOL); + CASE_CODE (SC_ERR_INVALID_HASH); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 28a50cff4e..63eee8ec3b 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -316,6 +316,7 @@ typedef enum { SC_ERR_SSH_LOG_GENERIC, SC_ERR_NIC_OFFLOADING, SC_ERR_NO_FILES_FOR_PROTOCOL, + SC_ERR_INVALID_HASH, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-file.h b/src/util-file.h index bdea4702f6..96fee17a90 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -35,12 +35,16 @@ #define FILE_NOMAGIC 0x0002 #define FILE_NOMD5 0x0004 #define FILE_MD5 0x0008 -#define FILE_LOGGED 0x0010 -#define FILE_NOSTORE 0x0020 -#define FILE_STORE 0x0040 -#define FILE_STORED 0x0080 -#define FILE_NOTRACK 0x0100 /**< track size of file */ -#define FILE_USE_DETECT 0x0200 /**< use content_inspected tracker */ +#define FILE_NOSHA1 0x0010 +#define FILE_SHA1 0x0020 +#define FILE_NOSHA256 0x0040 +#define FILE_SHA256 0x0080 +#define FILE_LOGGED 0x0100 +#define FILE_NOSTORE 0x0200 +#define FILE_STORE 0x0400 +#define FILE_STORED 0x0800 +#define FILE_NOTRACK 0x1000 /**< track size of file */ +#define FILE_USE_DETECT 0x2000 /**< use content_inspected tracker */ typedef enum FileState_ { FILE_STATE_NONE = 0, /**< no state */ @@ -66,6 +70,10 @@ typedef struct File_ { #ifdef HAVE_NSS HASHContext *md5_ctx; uint8_t md5[MD5_LENGTH]; + HASHContext *sha1_ctx; + uint8_t sha1[SHA1_LENGTH]; + HASHContext *sha256_ctx; + uint8_t sha256[SHA256_LENGTH]; #endif uint64_t content_inspected; /**< used in pruning if FILE_USE_DETECT * flag is set */