clamav/libfreshclam/libfreshclam_internal.h
Valerie Snyder 13c4788f36
FIPS & FIPS-like limits on hash algs for cryptographic uses
ClamAV will not function when using a FIPS-enabled OpenSSL 3.x.
This is because ClamAV uses MD5 and SHA1 algorithms for a variety of
purposes including matching for malware detection, matching to prevent
false positives on known-clean files, and for verification of MD5-based
RSA digital signatures for determining CVD (signature database archive)
authenticity.

Interestingly, FIPS had been intentionally bypassed when creating hashes
based whole buffers and whole files (by descriptor or `FILE`-pointer):
78d4a9985a
Note: this bypassed FIPS the 1.x way with:
`EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);`

It was NOT disabled when using `cl_hash_init()` / `cl_update_hash()` /
`cl_finish_hash()`. That likely worked by coincidence in that the hash
was already calculated most of the time. It certainly would have made
use of those functions if the hash had not been calculated prior:
78d4a9985a/libclamav/matcher.c (L743)

Regardless, bypassing FIPS entirely is not the correct solution.
The FIPS restrictions against using MD5 and SHA1 are valid, particularly
when verifying CVD digital siganatures, but also I think when using a
hash to determine if the file is known-clean (i.e. the "clean cache" and
also MD5-based and SHA1-based FP signatures).

This commit extends the work to bypass FIPS using the newer 3.x method:
`md = EVP_MD_fetch(NULL, alg, "-fips");`

It does this for the legacy `cl_hash*()` functions including
`cl_hash_init()` / `cl_update_hash()` / `cl_finish_hash()`.
It also introduces extended versions that allow the caller to choose if
they want to bypass FIPS:
- `cl_hash_data_ex()`
- `cl_hash_init_ex()`
- `cl_update_hash_ex()`
- `cl_finish_hash_ex()`
- `cl_hash_destroy_ex()`
- `cl_hash_file_fd_ex()`
See the `flags` parameter for each.

Ironically, this commit does NOT use the new functions at this time.
The rational is that ClamAV may need MD5, SHA1, and SHA-256 hashes of
the same files both for determining if the file is malware, and for
determining if the file is clean.

So instead, this commit will do a checks when:

1. Creating a new ClamAV scanning engine. If FIPS-mode enabled, it will
   automatically toggle the "FIPS limits" engine option.
   When loading signatures, if the engine "FIPS limits" option is enabled,
   then MD5 and SHA1 FP signatures will be skipped.

2. Before verifying a CVD (e.g. also for loading, unpacking when
   verification enabled).
   If "FIPS limits" or FIPS-mode are enabled, then the legacy MD5-based RSA
   method is disabled.

   Note: This commit also refactors the interface for `cl_cvdverify_ex()`
   and `cl_cvdunpack_ex()` so they take a `flags` parameters, rather than a
   single `bool`. As these functions are new in this version, it does not
   break the ABI.

The cache was already switched to use SHA2-256, so that's not a concern
for checking FIPS-mode / FIPS limits options.

This adds an option for `freshclam.conf` and `clamd.conf`:

   FIPSCryptoHashLimits yes

And an equivalent command-line option for `clamscan` and `sigtool`:

   --fips-limits

You may programmatically enable FIPS-limits for a ClamAV engine like this:
```C
   cl_engine_set_num(engine, CL_ENGINE_FIPS_LIMITS, 1);
```

CLAM-2792
2025-08-14 22:39:15 -04:00

102 lines
3 KiB
C

/*
* Copyright (C) 2013-2025 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2007-2013 Sourcefire, Inc.
* Copyright (C) 2002-2007 Tomasz Kojm <tkojm@clamav.net>
*
* This program is free software; you can redistribute it and/or modify
* it 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
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#ifndef __LIBFRESHCLAM_INTERNAL_H
#define __LIBFRESHCLAM_INTERNAL_H
#include "clamav-types.h"
// clang-format off
#define DNS_UPDATEINFO_NEWVERSION 0
#define DNS_UPDATEINFO_RECORDTIME 3
#define DNS_UPDATEINFO_VERSIONWARNING 4
#define DNS_UPDATEINFO_REMOTEFLEVEL 5
#define DNS_EXTRADBINFO_RECORDTIME 1
// clang-format on
#define SIZEOF_UUID_V4 37 /** For uuid_v4_gen(), includes NULL byte */
#define MIRRORS_DAT_MAGIC "FreshClamData" /** Magic bytes for freshclam.dat found before freshclam_dat_v1_t */
typedef struct _freshclam_dat_v1 {
uint32_t version; /** version of this dat format */
char uuid[SIZEOF_UUID_V4]; /** uuid to be used in user-agent */
time_t retry_after; /** retry date. If > 0, don't update until after this date */
} freshclam_dat_v1_t;
/*Length of a cf-ray id.*/
#define CFRAY_LEN 20
/* ----------------------------------------------------------------------------
* Internal libfreshclam globals
*/
extern fccb_download_complete g_cb_download_complete;
extern char *g_localIP;
extern char *g_userAgent;
extern char *g_proxyServer;
extern uint16_t g_proxyPort;
extern char *g_proxyUsername;
extern char *g_proxyPassword;
extern char *g_tempDirectory;
extern char *g_databaseDirectory;
extern void *g_signVerifier;
extern uint32_t g_maxAttempts;
extern uint32_t g_connectTimeout;
extern uint32_t g_requestTimeout;
extern uint32_t g_bCompressLocalDatabase;
extern freshclam_dat_v1_t *g_freshclamDat;
extern uint8_t g_lastRay[CFRAY_LEN + 1];
extern bool g_bFipsLimits;
fc_error_t load_freshclam_dat(void);
fc_error_t save_freshclam_dat(void);
fc_error_t new_freshclam_dat(void);
fc_error_t updatedb(
const char *database,
const char *dnsUpdateInfo,
char *server,
int bPrivateMirror,
void *context,
int bScriptedUpdates,
int logerr,
int *signo,
char **dbFilename,
int *bUpdated);
fc_error_t updatecustomdb(
const char *url,
void *context,
int logerr,
int *signo,
char **dbFilename,
int *bUpdated);
#define DNS_WARNING_THRESHOLD_HOURS 12
#define DNS_WARNING_THRESHOLD_SECONDS (DNS_WARNING_THRESHOLD_HOURS * 60 * 60)
#endif // __LIBFRESHCLAM_INTERNAL_H