@@ -134,6 +134,11 @@ void setup_curl_handle(CURL *handle)
134134 if (verbose != NULL ){
135135 curl_easy_setopt (handle , CURLOPT_VERBOSE , 1L );
136136 }
137+
138+ const char * ca_bundle = ca_bundle_path ();
139+ if (ca_bundle != NULL ) {
140+ curl_easy_setopt (handle , CURLOPT_CAINFO , ca_bundle );
141+ }
137142}
138143
139144
@@ -785,3 +790,77 @@ void range_fetch_end(struct range_fetch *rf) {
785790 free (rf -> url );
786791 free (rf );
787792}
793+
794+ // returns non-zero ("true") on success, 0 ("false") on failure
795+ int file_exists (const char * path ) {
796+ struct stat statbuf = {};
797+
798+ if (stat (path , & statbuf ) == 0 ) {
799+ return 1 ;
800+ }
801+
802+ const int error = errno ;
803+ if (error != ENOENT ) {
804+ fprintf (stderr , "zsync2: Unknown error while checking whether file %s exists: %s\n" , path , strerror (error ));
805+ }
806+
807+ return 0 ;
808+ }
809+
810+ // memory returned by this function must not be freed by the user
811+ const char * ca_bundle_path () {
812+ // in case the user specifies a custom file, we use this one instead
813+ // TODO: consider merging the user-specified file with the system CA bundle into a temp file
814+ const char * path_from_environment = getenv ("SSL_CERT_FILE" );
815+
816+ if (path_from_environment != NULL ) {
817+ return path_from_environment ;
818+ }
819+
820+ #if CURL_AT_LEAST_VERSION (7 , 84 , 0 )
821+ {
822+ // (very) recent libcurl versions provide us with a way to query the build-time search path they
823+ // use to find a suitable (distro-provided) CA certificate bundle they can hardcode
824+ // we can use this value to search for a bundle dynamically in the application
825+ CURL * curl = curl_easy_init ();
826+
827+ if (curl != NULL ) {
828+ CURLcode res ;
829+ char * curl_provided_path = NULL ;
830+
831+ curl_easy_getinfo (curl , CURLINFO_CAINFO , & curl_provided_path );
832+
833+ // should be safe to delete the handle and use the returned value, since it is allocated statically within libcurl
834+ curl_easy_cleanup (curl );
835+
836+ if (curl_provided_path != NULL ) {
837+ if (file_exists (curl_provided_path )) {
838+ return curl_provided_path ;
839+ }
840+ }
841+ }
842+ }
843+ #endif
844+
845+ // this list is a compilation of other AppImage projects' lists and the one used in libcurl's build system's autodiscovery
846+ // should cover most Linux distributions
847+ static const char * const possible_ca_bundle_paths [] = {
848+ "/etc/pki/tls/cacert.pem" ,
849+ "/etc/pki/tls/cert.pem" ,
850+ "/etc/pki/tls/certs/ca-bundle.crt" ,
851+ "/etc/ssl/ca-bundle.pem" ,
852+ "/etc/ssl/cert.pem" ,
853+ "/etc/ssl/certs/ca-certificates.crt" ,
854+ "/usr/local/share/certs/ca-root-nss.crt" ,
855+ "/usr/share/ssl/certs/ca-bundle.crt" ,
856+ };
857+
858+ for (size_t i = 0 ; i < sizeof (possible_ca_bundle_paths ); ++ i ) {
859+ const char * path_to_check = possible_ca_bundle_paths [i ];
860+ if (file_exists (path_to_check )) {
861+ return path_to_check ;
862+ }
863+ }
864+
865+ return NULL ;
866+ }
0 commit comments