int XzCheck_Final(CXzCheck *p, Byte *digest) { switch (p->mode) { case XZ_CHECK_CRC32: SetUi32(digest, CRC_GET_DIGEST(p->crc)); break; case XZ_CHECK_CRC64: { int i; UInt64 v = CRC64_GET_DIGEST(p->crc64); for (i = 0; i < 8; i++, v >>= 8) digest[i] = (Byte)(v & 0xFF); break; } case XZ_CHECK_SHA256: if (!(p->sha)) return 0; cl_finish_hash(p->sha, digest); break; default: return 0; } return 1; }
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; }
/* * 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; }
static void xar_hash_final(void * hash_ctx, void * result, int hash) { if (!hash_ctx || !result) return; switch (hash) { case XAR_CKSUM_OTHER: case XAR_CKSUM_NONE: return; } cl_finish_hash(hash_ctx, result); }
/* 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; }
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; }
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; }
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; }
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; }