Skip to content

Commit

Permalink
Extend freshclam client key/cert auth to macOS and Windows
Browse files Browse the repository at this point in the history
Also:
- Rename to use FRESHCLAM_CLIENT_CERT, FRESHCLAM_CLIENT_KEY instead
  prefixing with "CURL_". Unlike CURL_CA_BUNDLE, these variable names
  are not used by the `curl` program and so do not piggyback on that
  existing functionality.

- Add FRESHCLAM_CLIENT_KEY_PASSWD environment variable to support
  password protected private key PEM files, as described in:
  https://curl.se/libcurl/c/CURLOPT_SSLCERT.html

- Document the new environment variable options in the manpage and in
  the `freshclam --help` message. Also add missing documentation in the
  freshclam and clamsubmit help-messages for CURL_CA_BUNDLE.

- Update the NEWS.md file to credit jedrzej for the new feature.
  • Loading branch information
micahsnyder committed Aug 4, 2023
1 parent ab288d5 commit eb139c6
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 29 deletions.
13 changes: 13 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,26 @@ ClamAV 1.2.0 includes the following improvements and changes:

### Major changes

- Added ability for Freshclam to use a client certificate PEM file and a
private key PEM file for authentication to a private mirror by setting the
following environment variables:
- `FRESHCLAM_CLIENT_CERT`: May be set to the path of a file (PEM) containing
the client certificate.
- `FRESHCLAM_CLIENT_KEY`: May be set to the path of a file (PEM) containing
the client private key.
- `FRESHCLAM_CLIENT_KEY_PASSWD`: May be set to a password for the client key
PEM file, if it is password protected.

Patch courtesy of jedrzej.

## Other improvements

### Bug fixes

### Acknowledgments

Special thanks to the following people for code contributions and bug reports:
- jedrzej

## 1.1.0

Expand Down
2 changes: 2 additions & 0 deletions clamsubmit/clamsubmit.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ int main(int argc, char *argv[])
logg(LOGG_ERROR, "ERROR: Failed to set SSL CTX function!\n");
}
#else
/* Use an alternate CA bundle, if specified by the CURL_CA_BUNDLE environment variable. */
set_tls_ca_bundle(clam_curl);
#endif

Expand Down Expand Up @@ -466,6 +467,7 @@ int main(int argc, char *argv[])
logg(LOGG_ERROR, "ERROR: Failed to set SSL CTX function!\n");
}
#else
/* Use an alternate CA bundle, if specified by the CURL_CA_BUNDLE environment variable. */
set_tls_ca_bundle(aws_curl);
#endif

Expand Down
32 changes: 32 additions & 0 deletions common/cert_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -697,3 +697,35 @@ CURLcode sslctx_function(CURL *curl, void *ssl_ctx, void *userptr)

return status;
}

void set_tls_client_certificate(CURL *curl)
{
char *client_certificate;
char *client_key;
char *client_key_passwd;

client_certificate = getenv("FRESHCLAM_CLIENT_CERT");
if (client_certificate == NULL) {
return;
}

client_key = getenv("FRESHCLAM_CLIENT_KEY");
if (client_key == NULL) {
return;
}

client_key_passwd = getenv("FRESHCLAM_CLIENT_KEY_PASSWD");

/* set the cert for client authentication */
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(curl, CURLOPT_SSLCERT, client_certificate);

/* set the private key type and path */
curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
curl_easy_setopt(curl, CURLOPT_SSLKEY, client_key);

/* the private key may require a password */
if (client_key_passwd == NULL) {
curl_easy_setopt(curl, CURLOPT_KEYPASSWD, client_key_passwd);
}
}
10 changes: 8 additions & 2 deletions common/cert_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,20 @@

#if !(defined(C_DARWIN) || defined(_WIN32))
/**
* @brief Set the tls ca bundle to a custom value using the CURL_CA_BUNDLE env var
* @brief Set the tls ca bundle to a custom value using the CURL_CA_BUNDLE environment variable.
*
* @param curl Pointer to the curl connection handle.
*/
void set_tls_ca_bundle(CURL *curl);
void set_tls_client_certificate(CURL *curl);
#endif

/**
* @brief Set the path for a client certificate PEM file and a private key PEM file using the FRESHCLAM_CLIENT_CERT, FRESHCLAM_CLIENT_KEY, and FRESHCLAM_CLIENT_KEY_PASSWD environment variables.
*
* @param curl Pointer to the curl connection handle.
*/
void set_tls_client_certificate(CURL *curl);

/**
* @brief Load system and trusted root certificates into memory. Any errors
* while loading trusted certificates will be ignored. If error checking
Expand Down
25 changes: 2 additions & 23 deletions common/linux/cert_util_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,36 +38,15 @@ void set_tls_ca_bundle(CURL *curl)
char *ca_bundle;

ca_bundle = getenv("CURL_CA_BUNDLE");
if (ca_bundle == NULL)
if (ca_bundle == NULL) {
return;
}

if (curl_easy_setopt(curl, CURLOPT_CAINFO, ca_bundle) != CURLE_OK) {
fprintf(stderr, "Failed to set CURLOPT_CAINFO!\n");
}
}

void set_tls_client_certificate(CURL *curl)
{
char *client_certificate;
char *client_key;

client_certificate = getenv("CURL_CLIENT_CERT");
if (client_certificate == NULL)
return;

client_key = getenv("CURL_CLIENT_KEY");
if (client_key == NULL)
return;

/* set the cert for client authentication */
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(curl, CURLOPT_SSLCERT, client_certificate);

/* set the private key type and path */
curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
curl_easy_setopt(curl, CURLOPT_SSLKEY, client_key);
}

cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
{
cl_error_t ret = CL_EOPEN;
Expand Down
4 changes: 3 additions & 1 deletion docs/man/clamsubmit.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ The name of the virus detected as false positive. This option is required for fa
.LP
clamsubmit uses the following environment variables:
.TP
CURL_CA_BUNDLE - May be set to the path of a file (bundle) containing one or more CA certificates. This will override the default openssl certificate path.
\fBCURL_CA_BUNDLE\fR
(Linux/Unix only, excluding macOS) May be set to the path of a file (bundle) containing one or more CA certificates. This will override the default openssl certificate path.

.TP
Note that the CURL_CA_BUNDLE environment variable is also used by the curl command line tool for the same purpose.

.SH "AUTHOR"
Expand Down
13 changes: 12 additions & 1 deletion docs/man/freshclam.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,19 @@ With this option you can limit updates to a subset of database files. The DBNAME
.LP
freshclam uses the following environment variables:
.TP
CURL_CA_BUNDLE - May be set to the path of a file (bundle) containing one or more CA certificates. This will override the default openssl certificate path.
\fBCURL_CA_BUNDLE\fR
(Linux/Unix only, excluding macOS) May be set to the path of a file (bundle) containing one or more CA certificates. This will override the default openssl certificate path.
.TP
\fBFRESHCLAM_CLIENT_CERT\fR
May be set to the path of a file (PEM) containing the client certificate. This may be used for client authentication.
.TP
\fBFRESHCLAM_CLIENT_KEY\fR
May be set to the path of a file (PEM) containing the client private key. This is required if FRESHCLAM_CLIENT_CERT is set.
.TP
\fBFRESHCLAM_CLIENT_KEY_PASSWD\fR
May be set to a password for the client key PEM file. This is required if FRESHCLAM_CLIENT_KEY is set and the PEM file is password protected.

.TP
Note that the CURL_CA_BUNDLE environment variable is also used by the curl command line tool for the same purpose.

.SH "EXAMPLES"
Expand Down
23 changes: 22 additions & 1 deletion freshclam/freshclam.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ static void help(void)
printf(" --debug Enable debug messages\n");
printf(" --quiet Only output error messages\n");
printf(" --no-warnings Don't print and log warnings\n");
printf(" --stdout Write to stdout instead of stderr. Does not affect 'debug' messages.\n");
printf(" --stdout Write to stdout instead of stderr.\n");
printf(" Does not affect 'debug' messages.\n");
printf(" --show-progress Show download progress percentage\n");
printf("\n");
printf(" --config-file=FILE Read configuration from FILE.\n");
Expand All @@ -198,6 +199,26 @@ static void help(void)
printf(" --on-outdated-execute=COMMAND Execute COMMAND when software is outdated\n");
printf(" --update-db=DBNAME Only update database DBNAME\n");
printf("\n");
printf("Environment Variables:\n");
printf("\n");
#if !defined(C_DARWIN) && !defined(_WIN32)
printf(" CURL_CA_BUNDLE May be set to the path of a file (bundle)\n");
printf(" containing one or more CA certificates.\n");
printf(" This will override the default openssl\n");
printf(" certificate path.\n");
printf("\n");
#endif
printf(" FRESHCLAM_CLIENT_CERT May be set to the path of a file (PEM)\n");
printf(" containing the client certificate.\n");
printf(" This may be used for client authentication\n");
printf(" to a private mirror.\n");
printf(" FRESHCLAM_CLIENT_KEY May be set to the path of a file (PEM)\n");
printf(" containing the client private key.\n");
printf(" This is required if FRESHCLAM_CLIENT_CERT is set.\n");
printf(" FRESHCLAM_CLIENT_KEY_PASSWD May be set to a password for the client key PEM file.\n");
printf(" This is required if FRESHCLAM_CLIENT_KEY is\n");
printf(" set and the PEM file is password protected.\n");
printf("\n");
}

static void libclamav_msg_callback(enum cl_msg severity, const char *fullmsg, const char *msg, void *ctx)
Expand Down
5 changes: 4 additions & 1 deletion libfreshclam/libfreshclam_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -727,10 +727,13 @@ static fc_error_t create_curl_handle(
logg(LOGG_DEBUG, "create_curl_handle: Failed to set SSL CTX function. Your libcurl may use an SSL backend that does not support CURLOPT_SSL_CTX_FUNCTION.\n");
}
#else
/* Use an alternate CA bundle, if specified by the CURL_CA_BUNDLE environment variable. */
set_tls_ca_bundle(curl);
set_tls_client_certificate(curl);
#endif

/* Authenticate using a client certificate and private key, if specified by the FRESHCLAM_CLIENT_CERT, FRESHCLAM_CLIENT_KEY, and FRESHCLAM_CLIENT_KEY_PASSWD environment variables. */
set_tls_client_certificate(curl);

*curlHandle = curl;
status = FC_SUCCESS;

Expand Down

0 comments on commit eb139c6

Please sign in to comment.