diff --git a/NEWS.md b/NEWS.md index ad4baadbb7..ec699edcfe 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,18 @@ 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 @@ -16,6 +28,7 @@ ClamAV 1.2.0 includes the following improvements and changes: ### Acknowledgments Special thanks to the following people for code contributions and bug reports: +- jedrzej ## 1.1.0 diff --git a/clamsubmit/clamsubmit.c b/clamsubmit/clamsubmit.c index 0d38e890e3..4d71a5edf2 100644 --- a/clamsubmit/clamsubmit.c +++ b/clamsubmit/clamsubmit.c @@ -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 @@ -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 diff --git a/common/cert_util.c b/common/cert_util.c index c4f418fdf4..b65c0a5db9 100644 --- a/common/cert_util.c +++ b/common/cert_util.c @@ -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); + } +} diff --git a/common/cert_util.h b/common/cert_util.h index 20205095cb..cede5d1b61 100644 --- a/common/cert_util.h +++ b/common/cert_util.h @@ -24,11 +24,17 @@ #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); + +/** + * @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); #endif diff --git a/common/linux/cert_util_linux.c b/common/linux/cert_util_linux.c index 40dc89e03d..c2c0813250 100644 --- a/common/linux/cert_util_linux.c +++ b/common/linux/cert_util_linux.c @@ -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; diff --git a/docs/man/clamsubmit.1.in b/docs/man/clamsubmit.1.in index ffa42ad034..7502ab441a 100644 --- a/docs/man/clamsubmit.1.in +++ b/docs/man/clamsubmit.1.in @@ -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" diff --git a/docs/man/freshclam.1.in b/docs/man/freshclam.1.in index e230e70372..d194782297 100644 --- a/docs/man/freshclam.1.in +++ b/docs/man/freshclam.1.in @@ -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" diff --git a/freshclam/freshclam.c b/freshclam/freshclam.c index 694ac2bb8b..be230cdc56 100644 --- a/freshclam/freshclam.c +++ b/freshclam/freshclam.c @@ -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"); @@ -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) diff --git a/libfreshclam/libfreshclam_internal.c b/libfreshclam/libfreshclam_internal.c index 542d6cfe88..fdcbe32ba4 100644 --- a/libfreshclam/libfreshclam_internal.c +++ b/libfreshclam/libfreshclam_internal.c @@ -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;