diff --git a/src/etc/inc/certs.inc b/src/etc/inc/certs.inc index bb114c870d4..cbe792f811d 100644 --- a/src/etc/inc/certs.inc +++ b/src/etc/inc/certs.inc @@ -281,6 +281,42 @@ function ca_inter_create(& $ca, $keylen, $lifetime, $dn, $caref, $digest_alg = " return true; } +function ca_trustedcerts_generate() { + global $config, $g; + if (isset($config['system']['developerspew'])) { + $mt = microtime(); + echo "ca_trustedcerts_generate() being called $mt\n"; + } + + safe_mkdir("{$g['etc_path']}/ssl/certs"); + /* Remove all certs in the directory (but leave symlinks in place to allow power users to add trusted certs outside the Certificate Manager) */ + array_map('unlink', array_filter(glob("{$g['etc_path']}/ssl/certs/*"),function($x) { return is_file($x) && !is_link($x); })); + + if (is_array($config['ca'])) { + foreach ($config['ca'] as & $ca) { + if (isset($ca['trusted'])) { + $ca_hash = cert_get_hash($ca['crt']); + $ca_certfile = "{$g['etc_path']}/ssl/certs/{$ca_hash}.0"; + + /* Try again to unlink the specific cert file just in case a non-regular file (e.g. symlink) with the same hash exists */ + unlink_if_exists($ca_certfile); + $fd = fopen($ca_certfile, "w"); + if (!$fd) { + log_error(gettext( + "Error: cannot open {$g['etc_path']}/ssl/certs/{$ca_hash}.0 file in ca_trustedcerts_generate()." + )); + return 1; + } + + fwrite($fd, base64_decode($ca['crt'])); + fclose($fd); + } + } + } + + return 0; +} + function cert_import(& $cert, $crt_str, $key_str) { $cert['crt'] = base64_encode($crt_str); @@ -511,6 +547,11 @@ function cert_get_subject_hash($crt) { return $inf_crt['subject']; } +function cert_get_hash($crt) { + $inf_crt = openssl_x509_parse(base64_decode($crt)); + return $inf_crt['hash']; +} + function cert_get_issuer($str_crt, $decode = true) { if ($decode) { diff --git a/src/etc/inc/pfsense-utils.inc b/src/etc/inc/pfsense-utils.inc index 3e9767e1dea..ddc499a072d 100644 --- a/src/etc/inc/pfsense-utils.inc +++ b/src/etc/inc/pfsense-utils.inc @@ -1834,24 +1834,20 @@ function get_freebsd_version() { return $version[0]; } -function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) { +function get_curl_handle($url, $connect_timeout = 5, $timeout = 0, $verify_ssl = true, $follow_location = true, $verbose = false) { global $config, $g; - $fp = fopen($destination, "wb"); - - if (!$fp) { - return false; - } - $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $follow_location); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl); - curl_setopt($ch, CURLOPT_FILE, $fp); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout); - curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); - curl_setopt($ch, CURLOPT_HEADER, false); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_CAPATH, "{$g['etc_path']}/ssl/certs"); + curl_setopt($ch, CURLOPT_VERBOSE, $verbose); + if (!isset($config['system']['do_not_send_host_uuid'])) { curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid')); } else { @@ -1869,6 +1865,22 @@ function download_file($url, $destination, $verify_ssl = true, $connect_timeout } } + return $ch; +} + +function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) { + global $config, $g; + + $fp = fopen($destination, "wb"); + + if (!$fp) { + return false; + } + + $ch = get_curl_handle($url); + curl_setopt($ch, CURLOPT_FILE, $fp); + curl_setopt($ch, CURLOPT_HEADER, false); + @curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); fclose($fp); @@ -1898,32 +1910,10 @@ function download_file_with_progress_bar($url, $destination, $verify_ssl = true, * Originally by Author: Keyvan Minoukadeh * Modified by Scott Ullrich to return Content-Length size */ - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl); + $ch = get_curl_handle($url); curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header'); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody); - curl_setopt($ch, CURLOPT_NOPROGRESS, '1'); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout); - curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); - if (!isset($config['system']['do_not_send_host_uuid'])) { - curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid')); - } else { - curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']); - } - - if (!empty($config['system']['proxyurl'])) { - curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']); - if (!empty($config['system']['proxyport'])) { - curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']); - } - if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) { - @curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE); - curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}"); - } - } + curl_setopt($ch, CURLOPT_NOPROGRESS, true); @curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); diff --git a/src/etc/inc/services.inc b/src/etc/inc/services.inc index a37a9a39fca..01de11d079f 100644 --- a/src/etc/inc/services.inc +++ b/src/etc/inc/services.inc @@ -23,6 +23,8 @@ * limitations under the License. */ +require_once('pfsense-utils.inc'); + define('DYNDNS_PROVIDER_VALUES', 'all-inkl citynetwork cloudflare cloudflare-v6 custom custom-v6 dnsexit dnsimple dnsmadeeasy dnsomatic duiadns duiadns-v6 dyndns dyndns-custom dyndns-static dyns easydns eurodns freedns freedns-v6 glesys googledomains gratisdns he-net he-net-v6 he-net-tunnelbroker loopia namecheap noip noip-free ods opendns ovh-dynhost route53 selfhost spdyn spdyn-v6 zoneedit'); define('DYNDNS_PROVIDER_DESCRIPTIONS', 'All-Inkl.com,City Network,CloudFlare,CloudFlare (v6),Custom,Custom (v6),DNSexit,DNSimple,DNS Made Easy,DNS-O-Matic,DuiaDns.net,DuiaDns.net (v6),DynDNS (dynamic),DynDNS (custom),DynDNS (static),DyNS,easyDNS,Euro Dns,freeDNS,freeDNS (v6),GleSYS,Google Domains,GratisDNS,HE.net,HE.net (v6),HE.net Tunnelbroker,Loopia,Namecheap,No-IP,No-IP (free),ODS.org,OpenDNS,OVH DynHOST,Route 53,SelfHost,SPDYN,SPDYN (v6),ZoneEdit'); @@ -2032,12 +2034,8 @@ function dyndnsCheckIP($int) { } $hosttocheck = $url; - $ip_ch = curl_init($hosttocheck); - curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, $verifysslpeer); + $ip_ch = get_curl_handle($hosttocheck, 30, 120, $verifysslpeer); curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address); - curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30'); - curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120); curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); curl_setopt($ip_ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_setopt($ip_ch, CURLOPT_USERPWD, "{$username}:{$password}"); diff --git a/src/etc/pfSense-rc b/src/etc/pfSense-rc index 4b9990d345a..2cc1e9c69d1 100755 --- a/src/etc/pfSense-rc +++ b/src/etc/pfSense-rc @@ -340,6 +340,12 @@ mkdir -p /usr/local/openssl >/dev/null 2>&1 ln -sf /etc/ssl/openssl.cnf \ /usr/local/openssl/openssl.cnf +# Add environment variable to custom CA trusted roots directory +# Use SSL_CA_CERT_PATH environment variable per man fetch(3) +export SSL_CA_CERT_PATH=/etc/ssl/certs +# Use SSL_CERT_DIR environment variable per man SSL_CTX_load_verify_locations(3) +export SSL_CERT_DIR=/etc/ssl/certs + # Run the php.ini setup file and populate # /usr/local/etc/php.ini /etc/rc.php_ini_setup 2>/tmp/php_errors.txt diff --git a/src/etc/rc.bootup b/src/etc/rc.bootup index 60919e024c0..e5cd468a4ea 100755 --- a/src/etc/rc.bootup +++ b/src/etc/rc.bootup @@ -54,6 +54,8 @@ require_once("/etc/inc/filter.inc"); echo "."; require_once("/etc/inc/shaper.inc"); echo "."; +require_once("/etc/inc/certs.inc"); +echo "."; require_once("/etc/inc/ipsec.inc"); echo "."; require_once("/etc/inc/vpn.inc"); @@ -232,6 +234,9 @@ if (!$debugging) { /* re-make hosts file after configuring interfaces */ system_hosts_generate(); +/* add configured trusted CA certificates to /etc/ssl/certs */ +ca_trustedcerts_generate(); + /* start OpenVPN server & clients */ echo "Syncing OpenVPN settings..."; openvpn_resync_all(); diff --git a/src/usr/local/www/crash_reporter.php b/src/usr/local/www/crash_reporter.php index 101939f4fdc..803cea2fdef 100644 --- a/src/usr/local/www/crash_reporter.php +++ b/src/usr/local/www/crash_reporter.php @@ -40,13 +40,9 @@ function upload_crash_report($files) { $post["file{$counter}"] = "@{$file}"; $counter++; } - $ch = curl_init(); - curl_setopt($ch, CURLOPT_HEADER, 0); - curl_setopt($ch, CURLOPT_VERBOSE, 0); + $ch = get_curl_handle($g['crashreporterurl']); + curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']); - curl_setopt($ch, CURLOPT_URL, $g['crashreporterurl']); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); $response = curl_exec($ch); diff --git a/src/usr/local/www/system_camanager.php b/src/usr/local/www/system_camanager.php index 997ca8e816c..65be1ba728e 100644 --- a/src/usr/local/www/system_camanager.php +++ b/src/usr/local/www/system_camanager.php @@ -90,6 +90,7 @@ $name = $a_ca[$id]['descr']; unset($a_ca[$id]); write_config(); + ca_trustedcerts_generate(); $savemsg = sprintf(gettext("Certificate Authority %s and its CRLs (if any) successfully deleted."), htmlspecialchars($name)); pfSenseHeader("system_camanager.php"); exit; @@ -107,6 +108,7 @@ if (!empty($a_ca[$id]['prv'])) { $pconfig['key'] = base64_decode($a_ca[$id]['prv']); } + $pconfig['trusted'] = isset($a_ca[$id]['trusted']); } if ($act == "new") { @@ -250,6 +252,8 @@ $ca['descr'] = $pconfig['descr']; + $ca['trusted'] = isset($pconfig['trusted']); + if ($act == "edit") { $ca['descr'] = $pconfig['descr']; $ca['refid'] = $pconfig['refid']; @@ -312,6 +316,7 @@ if (!$input_errors) { write_config(); + ca_trustedcerts_generate(); pfSenseHeader("system_camanager.php"); } } @@ -362,6 +367,7 @@