From 2cf6ddcbb9e9aac46391678bf032f74295ee8d7d Mon Sep 17 00:00:00 2001 From: Nigel Graham Date: Sun, 24 May 2009 08:36:21 +0200 Subject: Added support for certificate chains to manager so that lighty can deliver them via SSL. --- etc/inc/captiveportal.inc | 4 +- etc/inc/certs.inc | 103 +++++++++++++++++++++++++++++++++++++++++++++ etc/inc/globals.inc | 2 +- etc/inc/system.inc | 20 ++++++++- etc/inc/upgrade_config.inc | 33 +++++++++++++++ 5 files changed, 158 insertions(+), 4 deletions(-) (limited to 'etc/inc') diff --git a/etc/inc/captiveportal.inc b/etc/inc/captiveportal.inc index 736763b..8414e89 100644 --- a/etc/inc/captiveportal.inc +++ b/etc/inc/captiveportal.inc @@ -223,13 +223,13 @@ EOD; $key = base64_decode($config['captiveportal']['private-key']); /* generate lighttpd configuration */ system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal-SSL.conf", - $cert, $key, "lighty-CaptivePortal-ssl.pid", "8001", "/usr/local/captiveportal/", + $cert, $key, "", "lighty-CaptivePortal-ssl.pid", "8001", "/usr/local/captiveportal/", "cert-portal.pem", "1", $maxproc, $use_fastcgi, true); } /* generate lighttpd configuration */ system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal.conf", - "", "", "lighty-CaptivePortal.pid", "8000", "/usr/local/captiveportal/", + "", "", "", "lighty-CaptivePortal.pid", "8000", "/usr/local/captiveportal/", "cert-portal.pem", "1", $maxproc, $use_fastcgi, true); /* attempt to start lighttpd */ diff --git a/etc/inc/certs.inc b/etc/inc/certs.inc index b7c0e60..40c0922 100644 --- a/etc/inc/certs.inc +++ b/etc/inc/certs.inc @@ -41,6 +41,20 @@ function & lookup_ca($refid) { return false; } +function & lookup_ca_by_subject($subject) { + global $config; + + if (is_array($config['system']['ca'])) + foreach ($config['system']['ca'] as & $ca) + { + $ca_subject = cert_get_subject($ca['crt']); + if ($ca_subject == $subject) + return $ca; + } + + return false; +} + function & lookup_cert($refid) { global $config; @@ -52,10 +66,70 @@ function & lookup_cert($refid) { return false; } +function ca_chain_array(& $cert) { + if($cert['caref']) { + $chain = array(); + $cert =& lookup_ca($cert['caref']); + $chain[] = $cert; + while ($cert) { + $caref = $cert['caref']; + if($caref) + $cert =& lookup_ca($caref); + else + $cert = false; + if($cert) + $chain[] = $cert; + } + return $chain; + } + return false; +} + +function ca_chain(& $cert) { + if($cert['caref']) { + $ca = ""; + $cas = ca_chain($cert); + if (is_array($cas)) + foreach ($cas as & $ca_cert) + { + $ca .= base64_decode($ca_cert['crt']); + $ca .= "\n"; + } + return $ca; + } + return false; +} + function ca_import(& $ca, $str) { + global $config; $ca['crt'] = base64_encode($str); + $subject = cert_get_subject($str, false); + $issuer = cert_get_issuer($str, false); + + // Find my issuer unless self-signed + if($issuer <> $subject) { + $issuer_crt =& lookup_ca_by_subject($issuer); + if($issuer_crt) + $ca['caref'] = $issuer_crt['refid']; + } + + /* Correct if child certificate was loaded first */ + if (is_array($config['system']['ca'])) + foreach ($config['system']['ca'] as & $oca) + { + $issuer = cert_get_issuer($oca['crt']); + if($ca['refid']<>$oca['refid'] && $issuer==$subject) + $oca['caref'] = $ca['refid']; + } + if (is_array($config['system']['cert'])) + foreach ($config['system']['cert'] as & $cert) + { + $issuer = cert_get_issuer($cert['crt']); + if($issuer==$subject) + $cert['caref'] = $ca['refid']; + } return true; } @@ -93,6 +167,15 @@ function cert_import(& $cert, $crt_str, $key_str) { $cert['crt'] = base64_encode($crt_str); $cert['prv'] = base64_encode($key_str); + $subject = cert_get_subject($crt_str, false); + $issuer = cert_get_issuer($crt_str, false); + + // Find my issuer unless self-signed + if($issuer <> $subject) { + $issuer_crt =& lookup_ca_by_subject($issuer); + if($issuer_crt) + $cert['caref'] = $issuer_crt['refid']; + } return true; } @@ -223,4 +306,24 @@ function cert_get_subject_array($crt) { return $subject_array; } +function cert_get_issuer($str_crt, $decode = true) { + + if ($decode) + $str_crt = base64_decode($str_crt); + + $inf_crt = openssl_x509_parse($str_crt); + $components = $inf_crt['issuer']; + + if (!is_array($components)) + return "unknown"; + foreach ($components as $a => $v) { + if (!strlen($issuer)) + $issuer = "{$a}={$v}"; + else + $issuer = "{$a}={$v}, {$issuer}"; + } + + return $issuer; +} + ?> diff --git a/etc/inc/globals.inc b/etc/inc/globals.inc index d8473b9..9955342 100644 --- a/etc/inc/globals.inc +++ b/etc/inc/globals.inc @@ -59,7 +59,7 @@ $g = array( "product_email" => "coreteam@pfsense.org", "hideplatform" => false, "debug" => false, - "latest_config" => "5.9", + "latest_config" => "6.0", "nopkg_platforms" => array("cdrom"), "minimum_ram_warning" => "115", "minimum_ram_warning_text" => "128 megabytes", diff --git a/etc/inc/system.inc b/etc/inc/system.inc index f05a3e9..6e8814d 100644 --- a/etc/inc/system.inc +++ b/etc/inc/system.inc @@ -509,6 +509,7 @@ function system_webgui_start() { $portarg = "80"; $crt = ""; $key = ""; + $ca = ""; /* non-standard port? */ if ($config['system']['webgui']['port']) @@ -522,13 +523,14 @@ function system_webgui_start() { $key = base64_decode($cert['prv']); if(!$config['system']['webgui']['port']) $portarg = "443"; + $ca = ca_chain($cert); } else log_error("Invalid webConfigurator https certificate, defaulting to http"); } /* generate lighttpd configuration */ system_generate_lighty_config("{$g['varetc_path']}/lighty-webConfigurator.conf", - $crt, $key, "lighty-webConfigurator.pid", $portarg, "/usr/local/www/"); + $crt, $key, $ca, "lighty-webConfigurator.pid", $portarg, "/usr/local/www/"); /* attempt to start lighthttpd */ $res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-webConfigurator.conf"); @@ -546,10 +548,12 @@ function system_webgui_start() { function system_generate_lighty_config($filename, $cert, $key, + $ca, $pid_file, $port = 80, $document_root = "/usr/local/www/", $cert_location = "cert.pem", + $ca_location = "ca.pem", $max_procs = 2, $max_requests = "1", $fast_cgi_enable = true, @@ -834,9 +838,11 @@ EOD; $cert = str_replace("\r", "", $cert); $key = str_replace("\r", "", $key); + $ca = str_replace("\r", "", $ca); $cert = str_replace("\n\n", "\n", $cert); $key = str_replace("\n\n", "\n", $key); + $ca = str_replace("\n\n", "\n", $ca); if($cert <> "" and $key <> "") { $fd = fopen("{$g['varetc_path']}/{$cert_location}", "w"); @@ -849,10 +855,22 @@ EOD; fwrite($fd, "\n"); fwrite($fd, $key); fclose($fd); + if($ca <> "") { + $fd = fopen("{$g['varetc_path']}/{$ca_location}", "w"); + if (!$fd) { + printf("Error: cannot open ca.pem in system_webgui_start().\n"); + return 1; + } + chmod("{$g['varetc_path']}/{$ca_location}", 0600); + fwrite($fd, $ca); + fclose($fd); + } $lighty_config .= "\n"; $lighty_config .= "## ssl configuration\n"; $lighty_config .= "ssl.engine = \"enable\"\n"; $lighty_config .= "ssl.pemfile = \"{$g['varetc_path']}/{$cert_location}\"\n\n"; + if($ca <> "") + $lighty_config .= "ssl.ca-file = \"{$g['varetc_path']}/{$ca_location}\"\n\n"; } $fd = fopen("{$filename}", "w"); diff --git a/etc/inc/upgrade_config.inc b/etc/inc/upgrade_config.inc index a3ea728..42ead89 100644 --- a/etc/inc/upgrade_config.inc +++ b/etc/inc/upgrade_config.inc @@ -1739,4 +1739,37 @@ function upgrade_058_to_059() { $schedl['schedlabel'] = uniqid(); } } + +function upgrade_059_to_060() { + global $config; + + if (is_array($config['system']['ca'])) + { + /* Locate issuer for all CAs */ + foreach ($config['system']['ca'] as & $ca) + { + $subject = cert_get_subject($ca['crt']); + $issuer = cert_get_issuer($ca['crt']); + if($issuer <> $subject) { + $issuer_crt =& lookup_ca_by_subject($issuer); + if($issuer_crt) + $ca['caref'] = $issuer_crt['refid']; + } + } + + /* Locate issuer for all certificates */ + if (is_array($config['system']['cert'])) + foreach ($config['system']['cert'] as & $cert) + { + $subject = cert_get_subject($cert['crt']); + $issuer = cert_get_issuer($cert['crt']); + if($issuer <> $subject) { + $issuer_crt =& lookup_ca_by_subject($issuer); + if($issuer_crt) + $cert['caref'] = $issuer_crt['refid']; + } + } + + } +} ?> -- cgit v1.1 From 801247db0d1ac947b2f6a4f4de14686c8f0b459a Mon Sep 17 00:00:00 2001 From: Nigel Graham Date: Tue, 26 May 2009 06:23:58 +0200 Subject: Fixed a problem in ca_chain that caused a segmentation fault. --- etc/inc/certs.inc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'etc/inc') diff --git a/etc/inc/certs.inc b/etc/inc/certs.inc index 40c0922..0e2341c 100644 --- a/etc/inc/certs.inc +++ b/etc/inc/certs.inc @@ -69,16 +69,16 @@ function & lookup_cert($refid) { function ca_chain_array(& $cert) { if($cert['caref']) { $chain = array(); - $cert =& lookup_ca($cert['caref']); - $chain[] = $cert; + $crt =& lookup_ca($cert['caref']); + $chain[] = $crt; while ($cert) { - $caref = $cert['caref']; + $caref = $crt['caref']; if($caref) - $cert =& lookup_ca($caref); + $crt =& lookup_ca($caref); else - $cert = false; - if($cert) - $chain[] = $cert; + $crt = false; + if($crt) + $chain[] = $crt; } return $chain; } @@ -88,7 +88,7 @@ function ca_chain_array(& $cert) { function ca_chain(& $cert) { if($cert['caref']) { $ca = ""; - $cas = ca_chain($cert); + $cas = ca_chain_array($cert); if (is_array($cas)) foreach ($cas as & $ca_cert) { @@ -97,7 +97,7 @@ function ca_chain(& $cert) { } return $ca; } - return false; + return ""; } function ca_import(& $ca, $str) { -- cgit v1.1 From 023f41803d42877e43241212923b22def948bf9c Mon Sep 17 00:00:00 2001 From: Nigel Graham Date: Tue, 26 May 2009 06:45:04 +0200 Subject: Found another bug in ca_chain_array. --- etc/inc/certs.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'etc/inc') diff --git a/etc/inc/certs.inc b/etc/inc/certs.inc index 0e2341c..936fc0a 100644 --- a/etc/inc/certs.inc +++ b/etc/inc/certs.inc @@ -71,7 +71,7 @@ function ca_chain_array(& $cert) { $chain = array(); $crt =& lookup_ca($cert['caref']); $chain[] = $crt; - while ($cert) { + while ($crt) { $caref = $crt['caref']; if($caref) $crt =& lookup_ca($caref); -- cgit v1.1 From 29dc1e6e81998c881c15c08c526d7de65ff8e76b Mon Sep 17 00:00:00 2001 From: Nigel Graham Date: Tue, 26 May 2009 08:14:56 +0200 Subject: Added a missing argument in the lighty configuration for captive portal. --- etc/inc/captiveportal.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'etc/inc') diff --git a/etc/inc/captiveportal.inc b/etc/inc/captiveportal.inc index 8414e89..4156e28 100644 --- a/etc/inc/captiveportal.inc +++ b/etc/inc/captiveportal.inc @@ -224,13 +224,13 @@ EOD; /* generate lighttpd configuration */ system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal-SSL.conf", $cert, $key, "", "lighty-CaptivePortal-ssl.pid", "8001", "/usr/local/captiveportal/", - "cert-portal.pem", "1", $maxproc, $use_fastcgi, true); + "cert-portal.pem", "ca-portal.pem", "1", $maxproc, $use_fastcgi, true); } /* generate lighttpd configuration */ system_generate_lighty_config("{$g['varetc_path']}/lighty-CaptivePortal.conf", "", "", "", "lighty-CaptivePortal.pid", "8000", "/usr/local/captiveportal/", - "cert-portal.pem", "1", $maxproc, $use_fastcgi, true); + "cert-portal.pem", "ca-portal.pem", "1", $maxproc, $use_fastcgi, true); /* attempt to start lighttpd */ $res = mwexec("/usr/local/sbin/lighttpd -f {$g['varetc_path']}/lighty-CaptivePortal.conf"); -- cgit v1.1