| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "daemon/common.h" |
| 4 | #include "netdata-conf-ssl.h" |
| 5 | #include <curl/curl.h> |
| 6 | |
| 7 | static bool is_ca_bundle_valid(const char *ca_path) { |
| 8 | if (!ca_path || !*ca_path) |
| 9 | return false; |
| 10 | |
| 11 | FILE *fp = fopen(ca_path, "r"); |
| 12 | if (!fp) |
| 13 | return false; |
| 14 | |
| 15 | ERR_clear_error(); |
| 16 | |
| 17 | int valid_certs = 0; |
| 18 | X509 *cert = NULL; |
| 19 | while ((cert = PEM_read_X509(fp, NULL, NULL, NULL)) != NULL) { |
| 20 | ASN1_TIME *not_after = X509_get_notAfter(cert); |
| 21 | int day, sec; |
| 22 | |
| 23 | if (ASN1_TIME_diff(&day, &sec, NULL, not_after) == 1) { |
| 24 | if (day > 0 || (day == 0 && sec > 0)) { |
| 25 | valid_certs++; |
| 26 | |
| 27 | // we found 1 valid, stop reading the file |
| 28 | X509_free(cert); |
| 29 | break; |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | X509_free(cert); |
| 34 | } |
| 35 | |
| 36 | fclose(fp); |
| 37 | |
| 38 | ERR_clear_error(); |
| 39 | return valid_certs > 0; |
| 40 | } |
| 41 | |
| 42 | const char *detect_libcurl_default_ca() { |
| 43 | #if LIBCURL_VERSION_NUM >= 0x074600 // 7.70.0 (CURLVERSION_SEVENTH) |
| 44 | curl_version_info_data *info = curl_version_info(CURLVERSION_NOW); |
| 45 | if (info) { |
| 46 | // Check built-in CA bundle |
| 47 | if (info->cainfo && |
| 48 | access(info->cainfo, R_OK) == 0 && |
| 49 | is_ca_bundle_valid(info->cainfo)) |
| 50 | return info->cainfo; |
| 51 | } |
| 52 | #endif |
| 53 | return NULL; |
| 54 | } |
| 55 | |
| 56 | static inline const char *detect_ca_path(void) { |
| 57 | static const char *paths[] = { |
| 58 | "/opt/netdata/etc/ssl/certs/ca-certificates.crt", // Netdata static build (needs to come first for consistency with standalone cURL in static builds) |
| 59 | "/etc/ssl/certs/ca-certificates.crt", // Debian, Ubuntu, Arch |
| 60 | "/etc/ssl/certs/ca-bundle.crt", // Rocky Linux (via symlinks) |
| 61 | "/etc/pki/tls/certs/ca-bundle.crt", // RHEL, CentOS, Fedora |
| 62 | "/etc/ssl/ca-bundle.pem", // OpenSUSE |
| 63 | "/etc/ssl/cert.pem", // Alpine |
| 64 | "/opt/netdata/share/ssl/certs/ca-certificates.crt", // Netdata static build - fallback |
| 65 | NULL |
| 66 | }; |
| 67 | |
| 68 | for (int i = 0; paths[i] != NULL; i++) { |
| 69 | if (access(paths[i], R_OK) == 0 && |
| 70 | is_ca_bundle_valid(paths[i])) |
| 71 | return paths[i]; |
| 72 | } |
| 73 | |
| 74 | return NULL; |
| 75 | } |
| 76 | |
| 77 | void netdata_conf_ssl(void) { |
| 78 | FUNCTION_RUN_ONCE(); |
| 79 | |
| 80 | netdata_ssl_initialize_openssl(); |
| 81 | |
| 82 | #if 0 |
| 83 | const char *p = getenv("CURL_CA_BUNDLE"); |
| 84 | if(!p || !*p) p = getenv("SSL_CERT_FILE"); |
| 85 | if(!p || !*p) { |
| 86 | p = X509_get_default_cert_file(); |
| 87 | if(!p || !*p || !is_ca_bundle_valid(p)) |
| 88 | p = NULL; |
| 89 | } |
| 90 | if(!p || !*p) p = detect_libcurl_default_ca(); |
| 91 | if(!p || !*p) p = detect_ca_path(); |
| 92 | setenv("CURL_CA_BUNDLE", inicfg_get(&netdata_config, CONFIG_SECTION_ENV_VARS, "CURL_CA_BUNDLE", p ? p : ""), 1); |
| 93 | setenv("SSL_CERT_FILE", inicfg_get(&netdata_config, CONFIG_SECTION_ENV_VARS, "SSL_CERT_FILE", p ? p : ""), 1); |
| 94 | #endif |
| 95 | |
| 96 | } |