Exemplo n.º 1
0
static void * xar_hash_init(int hash, void **sc, void **mc)
{
    if (!sc && !mc)
        return NULL;
    switch (hash) {
    case XAR_CKSUM_SHA1:
        *sc = cl_hash_init("sha1");
        if (!(*sc)) {
            return NULL;
        }

        return *sc;
    case XAR_CKSUM_MD5:
        *mc = cl_hash_init("md5");
        if (!(*mc)) {
            return NULL;
        }

        return *mc;
    case XAR_CKSUM_OTHER:
    case XAR_CKSUM_NONE:
    default:
        return NULL;
    }
}
Exemplo n.º 2
0
static int hash_match(const struct regex_matcher *rlist, const char *host, size_t hlen, const char *path, size_t plen, int *prefix_matched)
{
	const char *virname;
#if 0
	char s[1024];
	strncpy(s, host, hlen);
	strncpy(s+hlen, path, plen);
	s[hlen+plen] = '\0';
	cli_dbgmsg("hash lookup for: %s\n",s);
#endif
    UNUSEDPARAM(prefix_matched);

	if(rlist->sha256_hashes.bm_patterns) {
	    const char hexchars[] = "0123456789ABCDEF";
	    unsigned char h[65];
	    unsigned char sha256_dig[32];
	    unsigned i;
        void *sha256;

        sha256 = cl_hash_init("sha256");
        if (!(sha256))
            return CL_EMEM;

        cl_update_hash(sha256, (void *)host, hlen);
        cl_update_hash(sha256, (void *)path, plen);
        cl_finish_hash(sha256, sha256_dig);

	    for(i=0;i<32;i++) {
		h[2*i] = hexchars[sha256_dig[i]>>4];
		h[2*i+1] = hexchars[sha256_dig[i]&0xf];
	    }
	    h[64]='\0';
	    cli_dbgmsg("Looking up hash %s for %s(%u)%s(%u)\n", h, host, (unsigned)hlen, path, (unsigned)plen);
#if 0
	    if (prefix_matched) {
		if (cli_bm_scanbuff(sha256_dig, 4, &virname, NULL, &rlist->hostkey_prefix,0,NULL,NULL,NULL) == CL_VIRUS) {
		    cli_dbgmsg("prefix matched\n");
		    *prefix_matched = 1;
		} else
		    return CL_SUCCESS;
	    }
#endif
	    if (cli_bm_scanbuff(sha256_dig, 32, &virname, NULL, &rlist->sha256_hashes,0,NULL,NULL,NULL) == CL_VIRUS) {
		cli_dbgmsg("This hash matched: %s\n", h);
		switch(*virname) {
		    case 'W':
			cli_dbgmsg("Hash is whitelisted, skipping\n");
			break;
		    case '1':
			return CL_PHISH_HASH1;
		    case '2':
			return CL_PHISH_HASH2;
		    default:
			return CL_PHISH_HASH0;
		}
	    }
	}
	return CL_SUCCESS;
}
Exemplo n.º 3
0
/*
 * Since we're getting potentially sensitive data (MAC addresses for all devices on the system),
 * hash all the MAC addresses to provide basic anonymity and security.
 */
char *internal_get_host_id(void)
{
    size_t i;
    unsigned char raw_md5[16];
    char *printable_md5;
    struct device *devices;
    void *ctx;

    devices = get_devices();
    if (!(devices))
        return NULL;

    printable_md5 = calloc(1, 37);
    if (!(printable_md5)) {
        free(devices);
        return NULL;
    }

    ctx = cl_hash_init("md5");
    if (!(ctx)) {
        for (i=0; devices[i].name != NULL; i++)
            free(devices[i].name);

        free(devices);
        free(printable_md5);

        return NULL;
    }

    for (i=0; devices[i].name != NULL; i++)
        cl_update_hash(ctx, devices[i].mac, sizeof(devices[i].mac));

    cl_finish_hash(ctx, raw_md5);

    for (i=0; devices[i].name != NULL; i++)
        free(devices[i].name);
    free(devices);

    for (i=0; i < sizeof(raw_md5); i++) {
        size_t len = strlen(printable_md5);
        switch (len) {
            case 8:
            case 13:
            case 18:
            case 23:
                printable_md5[len++] = '-';
                break;
        }

        sprintf(printable_md5+len, "%02x", raw_md5[i]);
    }

    return printable_md5;
}
Exemplo n.º 4
0
void XzCheck_Init(CXzCheck *p, int mode)
{
  p->mode = mode;
  switch (mode)
  {
    case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break;
    case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break;
    case XZ_CHECK_SHA256:
        p->sha = cl_hash_init("sha256");
        break;
  }
}
Exemplo n.º 5
0
/* Hashes a file onto the provided buffer and looks it up the cache.
   Returns CL_VIRUS if found, CL_CLEAN if not FIXME or a recoverable error,
   and returns CL_EREAD if unrecoverable */
int cache_check(unsigned char *hash, cli_ctx *ctx) {
    fmap_t *map;
    size_t todo, at = 0;
    void *hashctx;
    int ret;

    if(!ctx || !ctx->engine || !ctx->engine->cache)
       return CL_VIRUS;

    if (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
        cli_dbgmsg("cache_check: Caching disabled. Returning CL_VIRUS.\n");
        return CL_VIRUS;
    }

    map = *ctx->fmap;
    todo = map->len;

    hashctx = cl_hash_init("md5");
    if (!(hashctx))
        return CL_VIRUS;


    while(todo) {
        const void *buf;
        size_t readme = todo < FILEBUFF ? todo : FILEBUFF;

        if(!(buf = fmap_need_off_once(map, at, readme))) {
            cl_hash_destroy(hashctx);
            return CL_EREAD;
        }

        todo -= readme;
        at += readme;

        if (cl_update_hash(hashctx, (void *)buf, readme)) {
            cl_hash_destroy(hashctx);
            cli_errmsg("cache_check: error reading while generating hash!\n");
            return CL_EREAD;
        }
    }

    cl_finish_hash(hashctx, hash);

    ret = cache_lookup_hash(hash, map->len, ctx->engine->cache, ctx->recursion);
    cli_dbgmsg("cache_check: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x is %s\n", hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], (ret == CL_VIRUS) ? "negative" : "positive");
    return ret;
}
Exemplo n.º 6
0
int cache_get_MD5(unsigned char *hash, cli_ctx *ctx)
{
    fmap_t *map;
    size_t todo, at = 0;
    void *hashctx;

    map = *ctx->fmap;
    todo = map->len;

    hashctx = cl_hash_init("md5");
    if (!(hashctx))
        return CL_VIRUS;

    while(todo) {
        const void *buf;
        size_t readme = todo < FILEBUFF ? todo : FILEBUFF;

        if(!(buf = fmap_need_off_once(map, at, readme))) {
            cl_hash_destroy(hashctx);
            return CL_EREAD;
        }

        todo -= readme;
        at += readme;

        if (cl_update_hash(hashctx, (void *)buf, readme)) {
            cl_hash_destroy(hashctx);
            cli_errmsg("cache_check: error reading while generating hash!\n");
            return CL_EREAD;
        }
    }

    cl_finish_hash(hashctx, hash);

    return CL_CLEAN;
}
Exemplo n.º 7
0
int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, unsigned char *refhash)
{
    const unsigned char *buff;
    int ret = CL_CLEAN, type = CL_CLEAN, bytes, compute_hash[CLI_HASH_AVAIL_TYPES];
    unsigned int i = 0, j = 0, bm_offmode = 0;
    uint32_t maxpatlen, offset = 0;
    struct cli_ac_data gdata, tdata;
    struct cli_bm_off toff;
    struct cli_pcre_off gpoff, tpoff;
    unsigned char digest[CLI_HASH_AVAIL_TYPES][32];
    struct cli_matcher *groot = NULL, *troot = NULL;
    struct cli_target_info info;
    fmap_t *map = *ctx->fmap;
    struct cli_matcher *hdb, *fp;
    const char *virname = NULL;
    uint32_t viruses_found = 0;
    void *md5ctx, *sha1ctx, *sha256ctx;

    if(!ctx->engine) {
        cli_errmsg("cli_scandesc: engine == NULL\n");
        return CL_ENULLARG;
    }

    md5ctx = cl_hash_init("md5");
    if (!(md5ctx))
        return CL_EMEM;

    sha1ctx = cl_hash_init("sha1");
    if (!(sha1ctx)) {
        cl_hash_destroy(md5ctx);
        return CL_EMEM;
    }

    sha256ctx = cl_hash_init("sha256");
    if (!(sha256ctx)) {
        cl_hash_destroy(md5ctx);
        cl_hash_destroy(sha1ctx);
        return CL_EMEM;
    }

    if(!ftonly)
        groot = ctx->engine->root[0]; /* generic signatures */

    if(ftype) {
        for(i = 1; i < CLI_MTARGETS; i++) {
            for (j = 0; j < cli_mtargets[i].target_count; ++j) {
                if(cli_mtargets[i].target[j] == ftype) {
                    troot = ctx->engine->root[i];
                    break;
                }
            }
            if (troot) break;
        }
    }

    if(ftonly) {
        if(!troot) {
            cl_hash_destroy(md5ctx);
            cl_hash_destroy(sha1ctx);
            cl_hash_destroy(sha256ctx);
            return CL_CLEAN;
        }

        maxpatlen = troot->maxpatlen;
    } else {
        if(troot)
            maxpatlen = MAX(troot->maxpatlen, groot->maxpatlen);
        else
            maxpatlen = groot->maxpatlen;
    }

    cli_targetinfo(&info, i, map);

    if(!ftonly) {
        if((ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(groot, &gdata, &info))) {
            if(info.exeinfo.section)
                free(info.exeinfo.section);

            cli_hashset_destroy(&info.exeinfo.vinfo);
            cl_hash_destroy(md5ctx);
            cl_hash_destroy(sha1ctx);
            cl_hash_destroy(sha256ctx);
            return ret;
        }
        if((ret = cli_pcre_recaloff(groot, &gpoff, &info, ctx))) {
            cli_ac_freedata(&gdata);
            if(info.exeinfo.section)
                free(info.exeinfo.section);

            cli_hashset_destroy(&info.exeinfo.vinfo);
            cl_hash_destroy(md5ctx);
            cl_hash_destroy(sha1ctx);
            cl_hash_destroy(sha256ctx);
            return ret;

        }
    }

    if(troot) {
        if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(troot, &tdata, &info))) {
            if(!ftonly) {
                cli_ac_freedata(&gdata);
                cli_pcre_freeoff(&gpoff);
            }
            if(info.exeinfo.section)
                free(info.exeinfo.section);

            cli_hashset_destroy(&info.exeinfo.vinfo);
            cl_hash_destroy(md5ctx);
            cl_hash_destroy(sha1ctx);
            cl_hash_destroy(sha256ctx);
            return ret;
        }
        if(troot->bm_offmode) {
            if(map->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) {
                if((ret = cli_bm_initoff(troot, &toff, &info))) {
                    if(!ftonly) {
                        cli_ac_freedata(&gdata);
                        cli_pcre_freeoff(&gpoff);
                    }

                    cli_ac_freedata(&tdata);
                    if(info.exeinfo.section)
                        free(info.exeinfo.section);

                    cli_hashset_destroy(&info.exeinfo.vinfo);
                    cl_hash_destroy(md5ctx);
                    cl_hash_destroy(sha1ctx);
                    cl_hash_destroy(sha256ctx);
                    return ret;
                }

                bm_offmode = 1;
            }
        }
        if ((ret = cli_pcre_recaloff(troot, &tpoff, &info, ctx))) {
            if(!ftonly) {
                cli_ac_freedata(&gdata);
                cli_pcre_freeoff(&gpoff);
            }

            cli_ac_freedata(&tdata);
            if(bm_offmode)
                cli_bm_freeoff(&toff);
            if(info.exeinfo.section)
                free(info.exeinfo.section);

            cli_hashset_destroy(&info.exeinfo.vinfo);
            cl_hash_destroy(md5ctx);
            cl_hash_destroy(sha1ctx);
            cl_hash_destroy(sha256ctx);
            return ret;
        }
    }

    hdb = ctx->engine->hm_hdb;
    fp = ctx->engine->hm_fp;

    if(!ftonly && hdb) {
        if(!refhash) {
            if(cli_hm_have_size(hdb, CLI_HASH_MD5, map->len) || cli_hm_have_size(fp, CLI_HASH_MD5, map->len)
               || cli_hm_have_wild(hdb, CLI_HASH_MD5) || cli_hm_have_wild(fp, CLI_HASH_MD5)) {
                compute_hash[CLI_HASH_MD5] = 1;
            } else {
                compute_hash[CLI_HASH_MD5] = 0;
            }
        } else {
            compute_hash[CLI_HASH_MD5] = 0;
            memcpy(digest[CLI_HASH_MD5], refhash, 16);
        }

        if(cli_hm_have_size(hdb, CLI_HASH_SHA1, map->len) || cli_hm_have_wild(hdb, CLI_HASH_SHA1)
            || cli_hm_have_size(fp, CLI_HASH_SHA1, map->len) || cli_hm_have_wild(fp, CLI_HASH_SHA1) ) {
            compute_hash[CLI_HASH_SHA1] = 1;
        } else {
            compute_hash[CLI_HASH_SHA1] = 0;
        }

        if(cli_hm_have_size(hdb, CLI_HASH_SHA256, map->len) || cli_hm_have_wild(hdb, CLI_HASH_SHA256)
            || cli_hm_have_size(fp, CLI_HASH_SHA256, map->len) || cli_hm_have_wild(fp, CLI_HASH_SHA256)) {
            compute_hash[CLI_HASH_SHA256] = 1;
        } else {
            compute_hash[CLI_HASH_SHA256] = 0;
        }
    }

    while(offset < map->len) {
        bytes = MIN(map->len - offset, SCANBUFF);
        if(!(buff = fmap_need_off_once(map, offset, bytes)))
            break;
        if(ctx->scanned)
            *ctx->scanned += bytes / CL_COUNT_PRECISION;

        if(troot) {
                virname = NULL;
                ret = matcher_run(troot, buff, bytes, &virname, &tdata, offset, &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, map, bm_offmode ? &toff : NULL, &tpoff, ctx);

            if (virname) {
                /* virname already appended by matcher_run */
                viruses_found = 1;
            }
            if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
                if(!ftonly) {
                    cli_ac_freedata(&gdata);
                    cli_pcre_freeoff(&gpoff);
                }

                cli_ac_freedata(&tdata);
                if(bm_offmode)
                    cli_bm_freeoff(&toff);
                cli_pcre_freeoff(&tpoff);

                if(info.exeinfo.section)
                    free(info.exeinfo.section);

                cli_hashset_destroy(&info.exeinfo.vinfo);
                cl_hash_destroy(md5ctx);
                cl_hash_destroy(sha1ctx);
                cl_hash_destroy(sha256ctx);
                return ret;
            }
        }

        if(!ftonly) {
            virname = NULL;
            ret = matcher_run(groot, buff, bytes, &virname, &gdata, offset, &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, map, NULL, &gpoff, ctx);

            if (virname) {
                /* virname already appended by matcher_run */
                viruses_found = 1;
            }
            if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
                cli_ac_freedata(&gdata);
                cli_pcre_freeoff(&gpoff);
                if(troot) {
                    cli_ac_freedata(&tdata);
                    if(bm_offmode)
                        cli_bm_freeoff(&toff);
                    cli_pcre_freeoff(&tpoff);
                }

                if(info.exeinfo.section)
                    free(info.exeinfo.section);

                cli_hashset_destroy(&info.exeinfo.vinfo);
                cl_hash_destroy(md5ctx);
                cl_hash_destroy(sha1ctx);
                cl_hash_destroy(sha256ctx);
                return ret;
            } else if((acmode & AC_SCAN_FT) && ret >= CL_TYPENO) {
                if(ret > type)
                    type = ret;
            }

            /* if (bytes <= (maxpatlen * (offset!=0))), it means the last window finished the file hashing *
             *   since the last window is responsible for adding intersection between windows (maxpatlen)  */
            if(hdb && (bytes > (maxpatlen * (offset!=0)))) {
                const void *data = buff + maxpatlen * (offset!=0);
                uint32_t data_len = bytes - maxpatlen * (offset!=0);

                if(compute_hash[CLI_HASH_MD5])
                    cl_update_hash(md5ctx, (void *)data, data_len);
                if(compute_hash[CLI_HASH_SHA1])
                    cl_update_hash(sha1ctx, (void *)data, data_len);
                if(compute_hash[CLI_HASH_SHA256])
                    cl_update_hash(sha256ctx, (void *)data, data_len);
            }
        }

        if(bytes < SCANBUFF)
            break;

        offset += bytes - maxpatlen;
    }

    if(!ftonly && hdb) {
        enum CLI_HASH_TYPE hashtype, hashtype2;

        if(compute_hash[CLI_HASH_MD5]) {
            cl_finish_hash(md5ctx, digest[CLI_HASH_MD5]);
            md5ctx = NULL;
        }
        if(refhash)
            compute_hash[CLI_HASH_MD5] = 1;
        if(compute_hash[CLI_HASH_SHA1]) {
            cl_finish_hash(sha1ctx, digest[CLI_HASH_SHA1]);
            sha1ctx = NULL;
        }
        if(compute_hash[CLI_HASH_SHA256]) {
            cl_finish_hash(sha256ctx, digest[CLI_HASH_SHA256]);
            sha256ctx = NULL;
        }

        virname = NULL;
        for(hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
            const char * virname_w = NULL;
            int found = 0;

            /* If no hash, skip to next type */
            if(!compute_hash[hashtype])
                continue;

            /* Do hash scan */
            if((ret = cli_hm_scan(digest[hashtype], map->len, &virname, hdb, hashtype)) == CL_VIRUS) {
                found += 1;
            }
            if(!found || SCAN_ALL) {
                if ((ret = cli_hm_scan_wild(digest[hashtype], &virname_w, hdb, hashtype)) == CL_VIRUS)
                    found += 2;
            }

            /* If found, do immediate hash-only FP check */
            if (found && fp) {
                for(hashtype2 = CLI_HASH_MD5; hashtype2 < CLI_HASH_AVAIL_TYPES; hashtype2++) {
                    if(!compute_hash[hashtype2])
                        continue;
                    if(cli_hm_scan(digest[hashtype2], map->len, NULL, fp, hashtype2) == CL_VIRUS) {
                        found = 0;
                        ret = CL_CLEAN;
                        break;
                    }
                    else if(cli_hm_scan_wild(digest[hashtype2], NULL, fp, hashtype2) == CL_VIRUS) {
                        found = 0;
                        ret = CL_CLEAN;
                        break;
                    }
                }
            }

            /* If matched size-based hash ... */
            if (found % 2) {
                viruses_found = 1;
                cli_append_virus(ctx, virname);
                if (!SCAN_ALL)
                    break;
                virname = NULL;
            }
            /* If matched size-agnostic hash ... */
            if (found > 1) {
                viruses_found = 1;
                cli_append_virus(ctx, virname_w);

                if (!SCAN_ALL)
                    break;
            }
        }
    }

    cl_hash_destroy(md5ctx);
    cl_hash_destroy(sha1ctx);
    cl_hash_destroy(sha256ctx);

    if(troot) {
        if(ret != CL_VIRUS || SCAN_ALL)
            ret = cli_exp_eval(ctx, troot, &tdata, &info, (const char *)refhash);
        if (ret == CL_VIRUS)
            viruses_found++;

        cli_ac_freedata(&tdata);
        if(bm_offmode)
            cli_bm_freeoff(&toff);
        cli_pcre_freeoff(&tpoff);
    }

    if(groot) {
        if(ret != CL_VIRUS || SCAN_ALL)
            ret = cli_exp_eval(ctx, groot, &gdata, &info, (const char *)refhash);
        cli_ac_freedata(&gdata);
        cli_pcre_freeoff(&gpoff);
    }

    if(info.exeinfo.section)
        free(info.exeinfo.section);

    cli_hashset_destroy(&info.exeinfo.vinfo);

    if (SCAN_ALL && viruses_found)
        return CL_VIRUS;
    if(ret == CL_VIRUS)
        return CL_VIRUS;

    return (acmode & AC_SCAN_FT) ? type : CL_CLEAN;
}
Exemplo n.º 8
0
static int asn1_parse_mscat(fmap_t *map, size_t offset, unsigned int size, crtmgr *cmgr, int embedded, const void **hashes, unsigned int *hashes_size, struct cl_engine *engine) {
    struct cli_asn1 asn1, deep, deeper;
    uint8_t sha1[SHA1_HASH_SIZE], issuer[SHA1_HASH_SIZE], md[SHA1_HASH_SIZE], serial[SHA1_HASH_SIZE];
    const uint8_t *message, *attrs;
    unsigned int dsize, message_size, attrs_size;
    cli_crt_hashtype hashtype;
    cli_crt *x509;
    void *ctx;
    int result;
    int isBlacklisted = 0;

    cli_dbgmsg("in asn1_parse_mscat\n");

    do {
	if(!(message = fmap_need_off_once(map, offset, 1))) {
	    cli_dbgmsg("asn1_parse_mscat: failed to read pkcs#7 entry\n");
	    break;
	}

	if(asn1_expect_objtype(map, message, &size, &asn1, 0x30)) /* SEQUENCE */
	    break;
	/* if(size) { */
	/*     cli_dbgmsg("asn1_parse_mscat: found extra data after pkcs#7 %u\n", size); */
	/*     break; */
	/* } */
	size = asn1.size;
	if(asn1_expect_obj(map, &asn1.content, &size, 0x06, lenof(OID_signedData), OID_signedData)) /* OBJECT 1.2.840.113549.1.7.2 - contentType = signedData */
	    break;
	if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0xa0)) /* [0] - content */
	    break;
	if(size) {
	    cli_dbgmsg("asn1_parse_mscat: found extra data in pkcs#7\n");
	    break;
	}
	size = asn1.size;
	if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30)) /* SEQUENCE */
	    break;
	if(size) {
	    cli_dbgmsg("asn1_parse_mscat: found extra data in signedData\n");
	    break;
	}
	size = asn1.size;
	if(asn1_expect_obj(map, &asn1.content, &size, 0x02, 1, "\x01")) /* INTEGER - VERSION 1 */
	    break;

	if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x31)) /* SET OF DigestAlgorithmIdentifier */
	    break;

	if(asn1_expect_algo(map, &asn1.content, &asn1.size, lenof(OID_sha1), OID_sha1)) /* DigestAlgorithmIdentifier[0] == sha1 */
	    break;
	if(asn1.size) {
	    cli_dbgmsg("asn1_parse_mscat: only one digestAlgorithmIdentifier is allowed\n");
	    break;
	}

	if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0x30)) /* SEQUENCE - contentInfo */
	    break;
	/* Here there is either a PKCS #7 ContentType Object Identifier for Certificate Trust List (szOID_CTL)
	 * or a single SPC_INDIRECT_DATA_OBJID */
	if(
	   (!embedded && asn1_expect_obj(map, &asn1.content, &asn1.size, 0x06, lenof(OID_szOID_CTL), OID_szOID_CTL)) ||
	   (embedded && asn1_expect_obj(map, &asn1.content, &asn1.size, 0x06, lenof(OID_SPC_INDIRECT_DATA_OBJID), OID_SPC_INDIRECT_DATA_OBJID))
	   )
	    break;

	if(asn1_expect_objtype(map, asn1.content, &asn1.size, &deep, 0xa0))
	    break;
	if(asn1.size) {
	    cli_dbgmsg("asn1_parse_mscat: found extra data in contentInfo\n");
	    break;
	}
	dsize = deep.size;
	if(asn1_expect_objtype(map, deep.content, &dsize, &deep, 0x30))
	    break;
	if(dsize) {
	    cli_dbgmsg("asn1_parse_mscat: found extra data in content\n");
	    break;
	}
	*hashes = deep.content;
	*hashes_size = deep.size;

	if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0xa0)) /* certificates */
	    break;

	dsize = asn1.size;
	if(dsize) {
	    crtmgr newcerts;
	    crtmgr_init(&newcerts);
	    while(dsize) {
		if(asn1_get_x509(map, &asn1.content, &dsize, cmgr, &newcerts)) {
		    dsize = 1;
		    break;
		}
	    }
	    if(dsize)
		break;
	    if(newcerts.crts) {
		x509 = newcerts.crts;
		cli_dbgmsg("asn1_parse_mscat: %u new certificates collected\n", newcerts.items);
		while(x509) {
		    cli_crt *parent = crtmgr_verify_crt(cmgr, x509);

            /* Dump the cert if requested before anything happens to it */
            if (engine->dconf->pe & PE_CONF_DUMPCERT) {
                char issuer[SHA1_HASH_SIZE*2+1], subject[SHA1_HASH_SIZE*2+1], serial[SHA1_HASH_SIZE*2+1];
                char mod[1024], exp[1024];
                int j=1024;

                fp_toradix_n(&x509->n, mod, 16, j);
                fp_toradix_n(&x509->e, exp, 16, j);
                for (j=0; j < SHA1_HASH_SIZE; j++) {
                    sprintf(&issuer[j*2], "%02x", x509->issuer[j]);
                    sprintf(&subject[j*2], "%02x", x509->subject[j]);
                    sprintf(&serial[j*2], "%02x", x509->serial[j]);
                }

                cli_dbgmsg_internal("cert subject:%s serial:%s pubkey:%s i:%s %lu->%lu %s %s %s\n", subject, serial, mod, issuer, (unsigned long)x509->not_before, (unsigned long)x509->not_after, x509->certSign ? "cert" : "", x509->codeSign ? "code" : "", x509->timeSign ? "time" : "");
            }

		    if(parent) {
                if (parent->isBlacklisted) {
                    isBlacklisted = 1;
                    cli_dbgmsg("asn1_parse_mscat: Authenticode certificate %s is revoked. Flagging sample as virus.\n", (parent->name ? parent->name : "(no name)"));
                }

			x509->codeSign &= parent->codeSign;
			x509->timeSign &= parent->timeSign;
            if(crtmgr_add(cmgr, x509))
                break;
            crtmgr_del(&newcerts, x509);
			x509 = newcerts.crts;
			continue;
		    }
		    x509 = x509->next;
		}
		if(x509)
		    break;
		if(newcerts.items)
		    cli_dbgmsg("asn1_parse_mscat: %u certificates did not verify\n", newcerts.items);
		crtmgr_free(&newcerts);
	    }
	}

	if(asn1_get_obj(map, asn1.next, &size, &asn1))
	    break;
	if(asn1.type == 0xa1 && asn1_get_obj(map, asn1.next, &size, &asn1)) /* crls - unused shouldn't be present */
	    break;
	if(asn1.type != 0x31) { /* signerInfos */
	    cli_dbgmsg("asn1_parse_mscat: unexpected type %02x for signerInfos\n", asn1.type);
	    break;
	}
	if(size) {
	    cli_dbgmsg("asn1_parse_mscat: unexpected extra data after signerInfos\n");
	    break;
	}
	size = asn1.size;
	if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30))
	    break;
	if(size) {
	    cli_dbgmsg("asn1_parse_mscat: only one signerInfo shall be present\n");
	    break;
	}
	size = asn1.size;
	if(asn1_expect_obj(map, &asn1.content, &size, 0x02, 1, "\x01")) /* Version = 1 */
	    break;
	if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30)) /* issuerAndSerialNumber */
	    break;
	dsize = asn1.size;
	if(asn1_expect_objtype(map, asn1.content, &dsize, &deep, 0x30)) /* issuer */
	    break;
	if(map_sha1(map, deep.content, deep.size, issuer))
	    break;

	if(asn1_expect_objtype(map, deep.next, &dsize, &deep, 0x02)) /* serial */
	    break;
	if(map_sha1(map, deep.content, deep.size, serial))
	    break;
	if(dsize) {
	    cli_dbgmsg("asn1_parse_mscat: extra data inside issuerAndSerialNumber\n");
	    break;
	}
	if(asn1_expect_algo(map, &asn1.next, &size, lenof(OID_sha1), OID_sha1)) /* digestAlgorithm == sha1 */
	    break;

	attrs = asn1.next;
	if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0xa0)) /* authenticatedAttributes */
	    break;
	attrs_size = (uint8_t *)(asn1.next) - attrs;
	if(attrs_size < 2) {
	    cli_dbgmsg("asn1_parse_mscat: authenticatedAttributes size is too small\n");
	    break;
	}

	dsize = asn1.size;
	deep.next = asn1.content;
	result = 0;
	while(dsize) {
	    struct cli_asn1 cobj;
	    int content;
	    if(asn1_expect_objtype(map, deep.next, &dsize, &deep, 0x30)) { /* attribute */
		dsize = 1;
		break;
	    }
	    if(asn1_expect_objtype(map, deep.content, &deep.size, &deeper, 0x06)) { /* attribute type */
		dsize = 1;
		break;
	    }
	    if(deeper.size != lenof(OID_contentType))
		continue;
	    if(!fmap_need_ptr_once(map, deeper.content, lenof(OID_contentType))) {
		cli_dbgmsg("asn1_parse_mscat: failed to read authenticated attribute\n");
		dsize = 1;
		break;
	    }
	    if(!memcmp(deeper.content, OID_contentType, lenof(OID_contentType)))
		content = 0; /* contentType */
	    else if(!memcmp(deeper.content, OID_messageDigest, lenof(OID_messageDigest)))
		content = 1; /* messageDigest */
	    else
		continue;
	    if(asn1_expect_objtype(map, deeper.next, &deep.size, &deeper, 0x31)) { /* set - contents */
		dsize = 1;
		break;
	    }
	    if(deep.size) {
		cli_dbgmsg("asn1_parse_mscat: extra data in authenticated attributes\n");
		dsize = 1;
		break;
	    }

	    if(result & (1<<content)) {
		cli_dbgmsg("asn1_parse_mscat: contentType or messageDigest appear twice\n");
		dsize = 1;
		break;
	    }

	    if(content == 0) { /* contentType */
		if(
		   (!embedded && asn1_expect_obj(map, &deeper.content, &deeper.size, 0x06, lenof(OID_szOID_CTL), OID_szOID_CTL)) || /* cat file */
		   (embedded && asn1_expect_obj(map, &deeper.content, &deeper.size, 0x06, lenof(OID_SPC_INDIRECT_DATA_OBJID), OID_SPC_INDIRECT_DATA_OBJID)) /* embedded cat */
		  ) {
		    dsize = 1;
		    break;
		}
		result |= 1;
	    } else { /* messageDigest */
		if(asn1_expect_objtype(map, deeper.content, &deeper.size, &cobj, 0x04)) {
		    dsize = 1;
		    break;
		}
		if(cobj.size != SHA1_HASH_SIZE) {
		    cli_dbgmsg("asn1_parse_mscat: messageDigest attribute has got the wrong size (%u)\n", cobj.size);
		    dsize = 1;
		    break;
		}
		if(!fmap_need_ptr_once(map, cobj.content, SHA1_HASH_SIZE)) {
		    cli_dbgmsg("asn1_parse_mscat: failed to read authenticated attribute\n");
		    dsize = 1;
		    break;
		}
		memcpy(md, cobj.content, SHA1_HASH_SIZE);
		result |= 2;
	    }
	    if(deeper.size) {
		cli_dbgmsg("asn1_parse_mscat: extra data in authenticated attribute\n");
		dsize = 1;
		break;
	    }
	}
	if(dsize)
	    break;
	if(result != 3) {
	    cli_dbgmsg("asn1_parse_mscat: contentType or messageDigest are missing\n");
	    break;
	}

	if(asn1_expect_algo(map, &asn1.next, &size, lenof(OID_rsaEncryption), OID_rsaEncryption)) /* digestEncryptionAlgorithm == sha1 */
	    break;

	if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0x04)) /* encryptedDigest */
	    break;
	if(asn1.size > 513) {
	    cli_dbgmsg("asn1_parse_mscat: encryptedDigest too long\n");
	    break;
	}
	if(map_sha1(map, *hashes, *hashes_size, sha1))
	    break;
	if(memcmp(sha1, md, sizeof(sha1))) {
	    cli_dbgmsg("asn1_parse_mscat: messageDigest mismatch\n");
	    break;
	}

	if(!fmap_need_ptr_once(map, attrs, attrs_size)) {
	    cli_dbgmsg("asn1_parse_mscat: failed to read authenticatedAttributes\n");
	    break;
	}

    ctx = cl_hash_init("sha1");
    if (!(ctx))
        break;

	cl_update_hash(ctx, "\x31", 1);
	cl_update_hash(ctx, (void *)(attrs + 1), attrs_size - 1);
	cl_finish_hash(ctx, sha1);

	if(!fmap_need_ptr_once(map, asn1.content, asn1.size)) {
	    cli_dbgmsg("asn1_parse_mscat: failed to read encryptedDigest\n");
	    break;
	}
	if(!(x509 = crtmgr_verify_pkcs7(cmgr, issuer, serial, asn1.content, asn1.size, CLI_SHA1RSA, sha1, VRFY_CODE))) {
	    cli_dbgmsg("asn1_parse_mscat: pkcs7 signature verification failed\n");
	    break;
	}
	message = asn1.content;
	message_size = asn1.size;

	if(!size) {
	    cli_dbgmsg("asn1_parse_mscat: countersignature is missing\n");
	    break;
	}

	if(size && asn1_expect_objtype(map, asn1.next, &size, &asn1, 0xa1)) /* unauthenticatedAttributes */
	    break;

	if(size) {
	    cli_dbgmsg("asn1_parse_mscat: extra data inside signerInfo\n");
	    break;
	}

	size = asn1.size;
	if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30))
	    break;
	if(size) {
	    cli_dbgmsg("asn1_parse_mscat: extra data inside unauthenticatedAttributes\n");
	    break;
	}

	size = asn1.size;
	/* 1.2.840.113549.1.9.6 - counterSignature */
	if(asn1_expect_obj(map, &asn1.content, &size, 0x06, lenof(OID_countersignature), OID_countersignature))
	    break;
	if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x31))
	    break;
	if(size) {
	    cli_dbgmsg("asn1_parse_mscat: extra data inside counterSignature\n");
	    break;
	}

	size = asn1.size;
	if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30))
	    break;
	if(size) {
	    cli_dbgmsg("asn1_parse_mscat: extra data inside unauthenticatedAttributes\n");
	    break;
	}

	size = asn1.size;
	if(asn1_expect_obj(map, &asn1.content, &size, 0x02, 1, "\x01")) /* Version = 1*/
	    break;

	if(asn1_expect_objtype(map, asn1.content, &size, &asn1, 0x30)) /* issuerAndSerialNumber */
	    break;

	if(asn1_expect_objtype(map, asn1.content, &asn1.size, &deep, 0x30)) /* issuer */
	    break;
	if(map_sha1(map, deep.content, deep.size, issuer))
	    break;

	if(asn1_expect_objtype(map, deep.next, &asn1.size, &deep, 0x02)) /* serial */
	    break;
	if(map_sha1(map, deep.content, deep.size, serial))
	    break;

	if(asn1.size) {
	    cli_dbgmsg("asn1_parse_mscat: extra data inside countersignature issuer\n");
	    break;
	}

	if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0x30)) /* digestAlgorithm */
	    break;
	if(asn1_expect_objtype(map, asn1.content, &asn1.size, &deep, 0x06))
	    break;
	if(deep.size != lenof(OID_sha1) && deep.size != lenof(OID_md5)) {
	    cli_dbgmsg("asn1_parse_mscat: wrong digestAlgorithm size\n");
	    break;
	}
	if(!fmap_need_ptr_once(map, deep.content, deep.size)) {
	    cli_dbgmsg("asn1_parse_mscat: failed to read digestAlgorithm OID\n");
	    break;
	}
	if(deep.size == lenof(OID_sha1) && !memcmp(deep.content, OID_sha1, lenof(OID_sha1))) {
	    hashtype = CLI_SHA1RSA;
	    if(map_sha1(map, message, message_size, md))
		break;
	} else if(deep.size == lenof(OID_md5) && !memcmp(deep.content, OID_md5, lenof(OID_md5))) {
	    hashtype = CLI_MD5RSA;
	    if(map_md5(map, message, message_size, md))
		break;
	} else {
	    cli_dbgmsg("asn1_parse_mscat: unknown digest oid in countersignature\n");
	    break;
	}
	if(asn1.size && asn1_expect_obj(map, &deep.next, &asn1.size, 0x05, 0, NULL))
	    break;
	if(asn1.size) {
	    cli_dbgmsg("asn1_parse_mscat: extra data in countersignature oid\n");
	    break;
	}

	attrs = asn1.next;
	if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0xa0)) /* authenticatedAttributes */
	    break;
	attrs_size = (uint8_t *)(asn1.next) - attrs;
	if(attrs_size < 2) {
	    cli_dbgmsg("asn1_parse_mscat: countersignature authenticatedAttributes are too small\n");
	    break;
	}
	result = 0;
	dsize = asn1.size;
	deep.next = asn1.content;
	while(dsize) {
	    int content;
	    if(asn1_expect_objtype(map, deep.next, &dsize, &deep, 0x30)) { /* attribute */
		dsize = 1;
		break;
	    }
	    if(asn1_expect_objtype(map, deep.content, &deep.size, &deeper, 0x06)) { /* attribute type */
		dsize = 1;
		break;
	    }
	    if(deeper.size != lenof(OID_contentType)) /* lenof(contentType) = lenof(messageDigest) = lenof(signingTime) = 9 */
		continue;

	    if(!fmap_need_ptr_once(map, deeper.content, lenof(OID_contentType))) {
		dsize = 1;
		break;
	    }
	    if(!memcmp(deeper.content, OID_contentType, lenof(OID_contentType)))
		content = 0; /* contentType */
	    else if(!memcmp(deeper.content, OID_messageDigest, lenof(OID_messageDigest)))
		content = 1; /* messageDigest */
	    else if(!memcmp(deeper.content, OID_signingTime, lenof(OID_signingTime)))
		content = 2; /* signingTime */
	    else
		continue;
	    if(result & (1<<content)) {
		cli_dbgmsg("asn1_parse_mscat: duplicate field in countersignature\n");
		dsize = 1;
		break;
	    }
	    result |= (1<<content);
	    if(asn1_expect_objtype(map, deeper.next, &deep.size, &deeper, 0x31)) { /* attribute type */
		dsize = 1;
		break;
	    }
	    if(deep.size) {
		cli_dbgmsg("asn1_parse_mscat: extra data in countersignature value\n");
		dsize = 1;
		break;
	    }
	    deep.size = deeper.size;
	    switch(content) {
	    case 0:  /* contentType = pkcs7-data */
		if(asn1_expect_obj(map, &deeper.content, &deep.size, 0x06, lenof(OID_pkcs7_data), OID_pkcs7_data))
		    deep.size = 1;
		else if(deep.size)
		    cli_dbgmsg("asn1_parse_mscat: extra data in countersignature content-type\n");
		break;
	    case 1:  /* messageDigest */
		if(asn1_expect_obj(map, &deeper.content, &deep.size, 0x04, (hashtype == CLI_SHA1RSA) ? SHA1_HASH_SIZE : 16, md)) {
		    deep.size = 1;
		    cli_dbgmsg("asn1_parse_mscat: countersignature hash mismatch\n");
		} else if(deep.size)
		    cli_dbgmsg("asn1_parse_mscat: extra data in countersignature message-digest\n");
		break;
	    case 2:  /* signingTime */
		{
		    time_t sigdate; /* FIXME shall i use it?! */
		    if(asn1_get_time(map, &deeper.content, &deep.size, &sigdate))
			deep.size = 1;
		    else if(deep.size)
			cli_dbgmsg("asn1_parse_mscat: extra data in countersignature signing-time\n");
		    else if(sigdate < x509->not_before || sigdate > x509->not_after) {
			cli_dbgmsg("asn1_parse_mscat: countersignature timestamp outside cert validity\n");
			deep.size = 1;
		    }
		    break;
		}
	    }
	    if(deep.size) {
		dsize = 1;
		break;
	    }
	}
	if(dsize)
	    break;
	if(result != 7) {
	    cli_dbgmsg("asn1_parse_mscat: some important attributes are missing in countersignature\n");
	    break;
	}

	if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0x30)) /* digestEncryptionAlgorithm == sha1 */
	    break;
	if(asn1_expect_objtype(map, asn1.content, &asn1.size, &deep, 0x06)) /* digestEncryptionAlgorithm == sha1 */
	    break;
	if(deep.size != lenof(OID_rsaEncryption)) { /* lenof(OID_rsaEncryption) = lenof(OID_sha1WithRSAEncryption) = 9 */
	    cli_dbgmsg("asn1_parse_mscat: wrong digestEncryptionAlgorithm size in countersignature\n");
	    break;
	}
	if(!fmap_need_ptr_once(map, deep.content, lenof(OID_rsaEncryption))) {
	    cli_dbgmsg("asn1_parse_mscat: cannot read digestEncryptionAlgorithm in countersignature\n");
	    break;
	}
	/* rsaEncryption or sha1withRSAEncryption */
	if(memcmp(deep.content, OID_rsaEncryption, lenof(OID_rsaEncryption)) && memcmp(deep.content, OID_sha1WithRSAEncryption, lenof(OID_sha1WithRSAEncryption))) {
	    cli_dbgmsg("asn1_parse_mscat: digestEncryptionAlgorithm in countersignature is not sha1\n");
	    break;
	}
	if(asn1.size && asn1_expect_obj(map, &deep.next, &asn1.size, 0x05, 0, NULL))
	    break;
	if(asn1.size) {
	    cli_dbgmsg("asn1_parse_mscat: extra data in digestEncryptionAlgorithm in countersignature\n");
	    break;
	}

	if(asn1_expect_objtype(map, asn1.next, &size, &asn1, 0x04)) /* encryptedDigest */
	    break;
	if(asn1.size > 513) {
	    cli_dbgmsg("asn1_parse_mscat: countersignature encryptedDigest too long\n");
	    break;
	}
	if(size) {
	    cli_dbgmsg("asn1_parse_mscat: extra data inside countersignature\n");
	    break;
	}
	if(!fmap_need_ptr_once(map, attrs, attrs_size)) {
	    cli_dbgmsg("asn1_parse_mscat: failed to read authenticatedAttributes\n");
	    break;
	}

	if(hashtype == CLI_SHA1RSA) {
        ctx = cl_hash_init("sha1");
        if (!(ctx))
            break;

        cl_update_hash(ctx, "\x31", 1);
        cl_update_hash(ctx, (void *)(attrs + 1), attrs_size - 1);
        cl_finish_hash(ctx, sha1);
	} else {
        ctx = cl_hash_init("md5");
        if (!(ctx))
            break;

        cl_update_hash(ctx, "\x31", 1);
        cl_update_hash(ctx, (void *)(attrs + 1), attrs_size - 1);
        cl_finish_hash(ctx, sha1);
	}

	if(!fmap_need_ptr_once(map, asn1.content, asn1.size)) {
	    cli_dbgmsg("asn1_parse_mscat: failed to read countersignature encryptedDigest\n");
	    break;
	}
	if(!crtmgr_verify_pkcs7(cmgr, issuer, serial, asn1.content, asn1.size, hashtype, sha1, VRFY_TIME)) {
	    cli_dbgmsg("asn1_parse_mscat: pkcs7 countersignature verification failed\n");
	    break;
	}

	cli_dbgmsg("asn1_parse_mscat: catalog successfully parsed\n");
    if (isBlacklisted) {
        return 1;
    }
	return 0;
    } while(0);

    cli_dbgmsg("asn1_parse_mscat: failed to parse catalog\n");
    return 1;
}
Exemplo n.º 9
0
static int cli_tgzload(int fd, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio, struct cli_dbinfo *dbinfo)
{
	char osize[13], name[101];
	char block[TAR_BLOCKSIZE];
	int nread, fdd, ret;
	unsigned int type, size, pad, compr = 1;
	off_t off;
	struct cli_dbinfo *db;
	unsigned char hash[32];

    cli_dbgmsg("in cli_tgzload()\n");

    if(lseek(fd, 512, SEEK_SET) < 0) {
        return CL_ESEEK;
    }

    if(cli_readn(fd, block, 7) != 7)
	return CL_EFORMAT; /* truncated file? */

    if(!strncmp(block, "COPYING", 7))
	compr = 0;

    if(lseek(fd, 512, SEEK_SET) < 0) {
        return CL_ESEEK;
    }

    if((fdd = dup(fd)) == -1) {
	cli_errmsg("cli_tgzload: Can't duplicate descriptor %d\n", fd);
	return CL_EDUP;
    }

    if(compr) {
	if((dbio->gzs = gzdopen(fdd, "rb")) == NULL) {
	    cli_errmsg("cli_tgzload: Can't gzdopen() descriptor %d, errno = %d\n", fdd, errno);
	    if (fdd > -1)
		close(fdd);
	    return CL_EOPEN;
	}
	dbio->fs = NULL;
    } else {
	if((dbio->fs = fdopen(fdd, "rb")) == NULL) {
	    cli_errmsg("cli_tgzload: Can't fdopen() descriptor %d, errno = %d\n", fdd, errno);
	    if (fdd > -1)
		close(fdd);
	    return CL_EOPEN;
	}
	dbio->gzs = NULL;
    }

    dbio->bufsize = CLI_DEFAULT_DBIO_BUFSIZE;
    dbio->buf = cli_malloc(dbio->bufsize);
    if(!dbio->buf) {
	cli_errmsg("cli_tgzload: Can't allocate memory for dbio->buf\n");
	cli_tgzload_cleanup(compr, dbio, fdd);
	return CL_EMALFDB;
    }
    dbio->bufpt = NULL;
    dbio->usebuf = 1;
    dbio->readpt = dbio->buf;

    while(1) {

	if(compr)
	    nread = gzread(dbio->gzs, block, TAR_BLOCKSIZE);
	else
	    nread = fread(block, 1, TAR_BLOCKSIZE, dbio->fs);

	if(!nread)
	    break;

	if(nread != TAR_BLOCKSIZE) {
	    cli_errmsg("cli_tgzload: Incomplete block read\n");
	    cli_tgzload_cleanup(compr, dbio, fdd);
	    return CL_EMALFDB;
	}

	if(block[0] == '\0')  /* We're done */
	    break;

	strncpy(name, block, 100);
	name[100] = '\0';

	if(strchr(name, '/')) {
	    cli_errmsg("cli_tgzload: Slash separators are not allowed in CVD\n");
	    cli_tgzload_cleanup(compr, dbio, fdd);
	    return CL_EMALFDB;
	}

	type = block[156];

	switch(type) {
	    case '0':
	    case '\0':
		break;
	    case '5':
		cli_errmsg("cli_tgzload: Directories are not supported in CVD\n");
		cli_tgzload_cleanup(compr, dbio, fdd);
		return CL_EMALFDB;
	    default:
		cli_errmsg("cli_tgzload: Unknown type flag '%c'\n", type);
		cli_tgzload_cleanup(compr, dbio, fdd);
		return CL_EMALFDB;
	}

	strncpy(osize, block + 124, 12);
	osize[12] = '\0';

	if((sscanf(osize, "%o", &size)) == 0) {
	    cli_errmsg("cli_tgzload: Invalid size in header\n");
	    cli_tgzload_cleanup(compr, dbio, fdd);
	    return CL_EMALFDB;
	}
	dbio->size = size;
	dbio->readsize = dbio->size < dbio->bufsize ? dbio->size : dbio->bufsize - 1;
	dbio->bufpt = NULL;
	dbio->readpt = dbio->buf;
    if (!(dbio->hashctx)) {
        dbio->hashctx = cl_hash_init("sha256");
        if (!(dbio->hashctx)) {
            cli_tgzload_cleanup(compr, dbio, fdd);
            return CL_EMALFDB;
        }
    }
	dbio->bread = 0;

	/* cli_dbgmsg("cli_tgzload: Loading %s, size: %u\n", name, size); */
	if(compr)
	    off = (off_t) gzseek(dbio->gzs, 0, SEEK_CUR);
	else
	    off = ftell(dbio->fs);

	if((!dbinfo && cli_strbcasestr(name, ".info")) || (dbinfo && (CLI_DBEXT(name) || cli_strbcasestr(name, ".ign") || cli_strbcasestr(name, ".ign2")))) {
	    ret = cli_load(name, engine, signo, options, dbio);
	    if(ret) {
		cli_errmsg("cli_tgzload: Can't load %s\n", name);
		cli_tgzload_cleanup(compr, dbio, fdd);
		return CL_EMALFDB;
	    }
	    if(!dbinfo) {
		cli_tgzload_cleanup(compr, dbio, fdd);
		return CL_SUCCESS;
	    } else {
		db = dbinfo;
		while(db && strcmp(db->name, name))
		    db = db->next;
		if(!db) {
		    cli_errmsg("cli_tgzload: File %s not found in .info\n", name);
		    cli_tgzload_cleanup(compr, dbio, fdd);
		    return CL_EMALFDB;
		}
		if(dbio->bread) {
		    if(db->size != dbio->bread) {
			cli_errmsg("cli_tgzload: File %s not correctly loaded\n", name);
			cli_tgzload_cleanup(compr, dbio, fdd);
			return CL_EMALFDB;
		    }
            cl_finish_hash(dbio->hashctx, hash);
            dbio->hashctx = cl_hash_init("sha256");
            if (!(dbio->hashctx)) {
                cli_tgzload_cleanup(compr, dbio, fdd);
                return CL_EMALFDB;
            }
		    if(memcmp(db->hash, hash, 32)) {
			cli_errmsg("cli_tgzload: Invalid checksum for file %s\n", name);
			cli_tgzload_cleanup(compr, dbio, fdd);
			return CL_EMALFDB;
		    }
		}
	    }
	}
	pad = size % TAR_BLOCKSIZE ? (TAR_BLOCKSIZE - (size % TAR_BLOCKSIZE)) : 0;
	if(compr) {
	    if(off == gzseek(dbio->gzs, 0, SEEK_CUR))
		gzseek(dbio->gzs, size + pad, SEEK_CUR);
	    else if(pad)
		gzseek(dbio->gzs, pad, SEEK_CUR);
	} else {
	    if(off == ftell(dbio->fs))
		fseek(dbio->fs, size + pad, SEEK_CUR);
	    else if(pad)
		fseek(dbio->fs, pad, SEEK_CUR);
	}
    }

    cli_tgzload_cleanup(compr, dbio, fdd);
    return CL_SUCCESS;
}