Skip to content

Commit

Permalink
Remove custom cert implementation in favor of system cert manager.
Browse files Browse the repository at this point in the history
  • Loading branch information
djmarcin committed Jan 24, 2017
1 parent 53ecaa9 commit 578946c
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 291 deletions.
5 changes: 1 addition & 4 deletions security/pfSense-pkg-stunnel/Makefile
Expand Up @@ -32,8 +32,6 @@ do-install:
${STAGEDIR}${PREFIX}/pkg
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/stunnel.inc \
${STAGEDIR}${PREFIX}/pkg
${INSTALL_DATA} -m 0644 ${FILESDIR}${PREFIX}/pkg/stunnel_certs.xml \
${STAGEDIR}${PREFIX}/pkg
${INSTALL_DATA} ${FILESDIR}/etc/inc/priv/stunnel.priv.inc \
${STAGEDIR}/etc/inc/priv
${INSTALL_DATA} ${FILESDIR}${PREFIX}/www/shortcuts/pkg_stunnel.inc \
Expand All @@ -42,7 +40,6 @@ do-install:
${STAGEDIR}${DATADIR}
@${REINPLACE_CMD} -i '' -e "s|%%PKGVERSION%%|${PKGVERSION}|" \
${STAGEDIR}${DATADIR}/info.xml \
${STAGEDIR}${PREFIX}/pkg/stunnel.xml \
${STAGEDIR}${PREFIX}/pkg/stunnel_certs.xml
${STAGEDIR}${PREFIX}/pkg/stunnel.xml

.include <bsd.port.mk>
Expand Up @@ -26,7 +26,6 @@ $priv_list['page-system-stunnel']['name'] = "WebCfg - System: stunnel package";
$priv_list['page-system-stunnel']['descr'] = "Allow access to stunnel package GUI";
$priv_list['page-system-stunnel']['match'] = array();
$priv_list['page-system-stunnel']['match'][] = "pkg_edit.php?xml=stunnel.xml*";
$priv_list['page-system-stunnel']['match'][] = "pkg_edit.php?xml=stunnel_certs.xml*";
$priv_list['page-services-stunnel']['match'][] = "shortcuts/pkg_stunnel.inc*";

?>
199 changes: 52 additions & 147 deletions security/pfSense-pkg-stunnel/files/usr/local/pkg/stunnel.inc
Expand Up @@ -22,115 +22,22 @@
require_once("config.inc");
require_once("util.inc");
require_once("pfsense-utils.inc");
require_once("certs.inc");

global $config;
define('STUNNEL_LOCALBASE', '/usr/local');
define('STUNNEL_ETCDIR', STUNNEL_LOCALBASE . "/etc/stunnel");
if (!isset($_GET['id']) and !isset($_POST['id'])) {
if ($GLOBALS['config']['installedpackages']['stunnelcerts']['savemsg']) {
$savemsg = $GLOBALS['config']['installedpackages']['stunnelcerts']['savemsg'];
unset($GLOBALS['config']['installedpackages']['stunnelcerts']['savemsg']);
write_config();
}
}
if (isset($_GET['id'])) {
$config['installedpackages']['stunnelcerts']['config'][$_GET['id']]['cert_chain'] =
base64_decode($config['installedpackages']['stunnelcerts']['config'][$_GET['id']]['cert_chain']);
$config['installedpackages']['stunnelcerts']['config'][$_GET['id']]['cert_key'] =
base64_decode($config['installedpackages']['stunnelcerts']['config'][$_GET['id']]['cert_key']);
}
$certs = $config['installedpackages']['stunnelcerts']['config'];
is_array($certs) ? $num_certs = count($certs) : $num_certs = 0;
if (!isset($_GET['id']) and !isset($_POST['id']) and $num_certs) {
for ($i = 0; $i < $num_certs; $i++) {
$cert = $certs[$i];
$_info = openssl_x509_parse(base64_decode($cert['cert_chain']));
$valid = floor(($_info['validTo_time_t'] - time()) / 86400);
if ($cert['cert_chain']) {
if (!openssl_x509_check_private_key(base64_decode($cert['cert_chain']), base64_decode($cert['cert_key']))) {
$_status = '<font color="#AA0000"><strong>Invalid key/cert!</strong></font>';
} elseif ($valid < 30) {
$_status = '<font color="#B27D4B">Expires in ' . $valid . ' days!</font>';
} else {
$_status = '<font color="#008800">OK (' . $valid . ' days)</font>';
}
$config['installedpackages']['stunnelcerts']['config'][$i]['status'] = $_status;
} else {
unset($config['installedpackages']['stunnelcerts']['config'][$i]);
}
}
}

// Initialize the list of tunnels.
$tunnels = $config['installedpackages']['stunnel']['config'];
is_array($tunnels) ? $num_tunnels = count($tunnels) : $num_tunnels = 0;
if (!isset($_GET['id']) and $num_tunnels) {
for ($i = 0; $i < $num_tunnels; $i++) {
$tunnel = $tunnels[$i];
if ($tunnel['certificate']) {
$certid = 0;
if (is_array($config['installedpackages']['stunnelcerts']['config'])) {
foreach ($config['installedpackages']['stunnelcerts']['config'] as $cert) {
if ($tunnel['certificate'] == $cert['filename']) {
$config['installedpackages']['stunnel']['config'][$i]['certificatelink']=
'<a href="/pkg_edit.php?xml=stunnel_certs.xml&act=edit&id=' . $certid . '">' . $cert['description'] . '</a>';
}
$certid++;
}
}
}
}
}
function stunnel_printcsr() {
// $GLOBALS['savemsg'] = "<pre>" . print_r($GLOBALS['config']['installedpackages']['stunnelcerts']['config'], true) . "</pre>";
}
function stunnel_addcerts($config) {
$certs=$config['installedpackages']['stunnelcerts']['config'];
$tunnels=$config['installedpackages']['stunnel']['config'];
?>
<script type="text/javascript">
//<![CDATA[
function addcerts() {
<?php
foreach ($certs as $cert) {
echo("document.forms['iform'].certificate.appendChild(new Option('".$cert['description']."', '".$cert['filename']."'));");
}
?>
}
addcerts();
for (var i=0; i < document.forms['iform'].certificate.length; i++) {
<?php
$filename=$tunnels[$_GET['id']]['certificate'];
echo('if (document.forms["iform"].certificate[i].value == "'.$filename.'") {');
?>
document.forms['iform'].certificate[i].selected = true;
} else {
document.forms['iform'].certificate[i].selected = false;
}
}
//]]>
</script>
<?php
}
function stunnel_disablefields() {
?>
<script type="text/javascript">
//<![CDATA[
document.forms['iform'].subject.readOnly=true;
document.forms['iform'].filename.readOnly=true;
document.forms['iform'].expiry.readOnly=true;
//]]>
</script>
<?php
}
function stunnel_delete($config) {
$cert=$config['installedpackages']['stunnelcerts']['config'][$_GET['id']];
if (isset($_GET['id'])) {
unlink_if_exists(STUNNEL_ETCDIR . '/' . $cert['filename'] . '.pem');
unlink_if_exists(STUNNEL_ETCDIR . '/' . $cert['filename'] . '.key');
unlink_if_exists(STUNNEL_ETCDIR . '/' . $cert['filename'] . '.chain');
}
}

function stunnel_save($config) {
$GLOBALS['config']['installedpackages']['stunnelcerts']['savemsg'] = '';
conf_mount_rw();
safe_mkdir(STUNNEL_ETCDIR, 0755);
$fout = fopen(STUNNEL_ETCDIR . "/stunnel.conf", "w");
Expand All @@ -141,15 +48,23 @@ function stunnel_save($config) {
if (!is_array($config['installedpackages']['stunnel']['config'])) {
$config['installedpackages']['stunnel']['config'] = array();
}

// Keep array of in-use certificates so we can clean up after ourselves.
$in_use_certs = array();
$in_use_certs[] = 'stunnel.pem';

foreach ($config['installedpackages']['stunnel']['config'] as $pkgconfig) {
fwrite($fout, "\n[" . $pkgconfig['description'] . "]\n");
if ($pkgconfig['client']) {
fwrite($fout, "client = yes" . "\n");
}
if ($pkgconfig['certificate']) {
if (file_exists(STUNNEL_ETCDIR . '/'.$pkgconfig['certificate'].'.key') and file_exists(STUNNEL_ETCDIR . '/'.$pkgconfig['certificate'].'.chain')) {
fwrite($fout, "key = " . STUNNEL_ETCDIR . "/" . $pkgconfig['certificate'] . ".key\n");
fwrite($fout, "cert = " . STUNNEL_ETCDIR . "/" . $pkgconfig['certificate'] . ".chain\n");
if ($pkgconfig['certificate'] && $pkgconfig['certificate'] != 'default') {
$cert = lookup_cert($pkgconfig['certificate']);
if ($cert != false) {
file_put_contents(STUNNEL_ETCDIR . "/{$pkgconfig['certificate']}.pem",
base64_decode($cert['prv']) . base64_decode($cert['crt']) . ca_chain($cert));
fwrite($fout, "cert = " . STUNNEL_ETCDIR . "/{$pkgconfig['certificate']}.pem\n");
$in_use_certs[] = "{$pkgconfig['certificate']}.pem";
}
}
if ($pkgconfig['sourceip']) {
Expand All @@ -160,59 +75,48 @@ function stunnel_save($config) {
fwrite($fout, "TIMEOUTclose = 0\n\n");
}
fclose($fout);

// Clean up certs that are no longer in use.
foreach (glob(STUNNEL_ETCDIR . "/*.pem") as $file) {
if (!in_array(basename($file), $in_use_certs)) {
unlink($file);
}
}

conf_mount_ro();
stop_service("stunnel");
start_service("stunnel");
}
function stunnel_save_cert($config) {
$GLOBALS['config']['installedpackages']['stunnelcerts']['savemsg'] = '';
if (isset($_POST['id'])) {
if (!$_POST['cert_chain']) {
$GLOBALS['config']['installedpackages']['stunnelcerts']['savemsg'] .= "Certificate chain must be specified!<br />";
}
if (!$_POST['cert_key']) {
$GLOBALS['config']['installedpackages']['stunnelcerts']['savemsg'] .= "RSA Key must be specified!<br />";
}
if ($_POST['cert_chain'] and $_POST['cert_key']) {
$_cert = openssl_x509_parse($_POST['cert_chain']);
if ($_cert['hash']) {
if (openssl_x509_check_private_key($_POST['cert_chain'], $_POST['cert_key'])) {
file_put_contents(STUNNEL_ETCDIR . '/'. $_cert['hash'] . '.key', $_POST['cert_key']);
file_put_contents(STUNNEL_ETCDIR . '/' . $_cert['hash'] . '.chain', $_POST['cert_chain']);
file_put_contents(STUNNEL_ETCDIR . '/' . $_cert['hash'] . '.pem', $_POST['cert_key']."\n".$_POST['cert_chain']);
system('chown stunnel:stunnel ' . STUNNEL_ETCDIR . '/*');
chmod(STUNNEL_ETCDIR . '/' . $_cert['hash'] . '.key', 0600);
chmod(STUNNEL_ETCDIR . '/' . $_cert['hash'] . '.pem', 0600);
$_POST['filename'] = $_cert['hash'];
$_POST['expiry_raw'] = $_cert['validTo_time_t'];
$_POST['expiry'] = date('Y-m-d', $_cert['validTo_time_t']);
$_POST['subject'] = $_cert['name'];
} else {
$GLOBALS['config']['installedpackages']['stunnelcerts']['savemsg'] .= "Certificate and key do not match!<br />";
$_POST['filename'] = '';
}
} else {
$GLOBALS['config']['installedpackages']['stunnelcerts']['savemsg'] .= "Couldn't parse certificate!<br />";
$_POST['expiry_raw'] = '';
$_POST['expiry'] = '';
$_POST['subject'] = '';
$_POST['filename'] = '';
}
}
$_POST['cert_key'] = base64_encode($_POST['cert_key']);
$_POST['cert_chain'] = base64_encode($_POST['cert_chain']);
$_fname = $GLOBALS['config']['installedpackages']['stunnelcerts']['config'][$_POST['id']]['filename'];
if ($_fname and $_fname != $_POST['filename']) {
unlink_if_exists(STUNNEL_ETCDIR . '/' . $_fname . '.chain');
unlink_if_exists(STUNNEL_ETCDIR . '/' . $_fname . '.key');
unlink_if_exists(STUNNEL_ETCDIR . '/' . $_fname . '.pem');
}
}
}

function stunnel_install() {
safe_mkdir(STUNNEL_ETCDIR);
system("/usr/bin/openssl req -new -x509 -days 365 -nodes -out " . STUNNEL_ETCDIR . "/stunnel.pem -keyout " . STUNNEL_ETCDIR . "/stunnel.pem 2>/dev/null");

// Generate a self-signed default certificate.
$cert = array();
$cert['refid'] = uniqid();
$cert['descr'] = sprintf(gettext("stunnel default (%s)"), $cert['refid']);

$dn = array(
'countryName' => "US",
'stateOrProvinceName' => "State",
'localityName' => "Locality",
'organizationName' => "{$g['product_name']} stunnel Self-Signed Certificate",
'emailAddress' => "admin@{$config['system']['hostname']}.{$config['system']['domain']}",
'commonName' => "{$config['system']['hostname']}-{$cert['refid']}");
$old_err_level = error_reporting(0); /* otherwise openssl_ functions throw warnings directly to a page screwing menu tab */
if (!cert_create($cert, null, 2048, 365, $dn, "self-signed", "sha256")) {
while ($ssl_err = openssl_error_string()) {
log_error(sprintf(gettext("Error creating WebGUI Certificate: openssl library returns: %s"), $ssl_err));
}
error_reporting($old_err_level);
return null;
}
error_reporting($old_err_level);

// Write the .pem file to the expected default location for stunnel and set up required permissions.
file_put_contents(STUNNEL_ETCDIR . "/stunnel.pem", base64_decode($cert['prv']) . base64_decode($cert['crt']));
chmod(STUNNEL_ETCDIR . "/stunnel.pem", 0600);

@mkdir("/var/tmp/stunnel/var/tmp/run/stunnel", 0755, true);
system("/usr/sbin/chown -R stunnel:stunnel /var/tmp/stunnel");
$_rcfile['file'] = 'stunnel.sh';
Expand All @@ -238,6 +142,7 @@ function stunnel_install() {
}
fclose($fout);
}

function stunnel_deinstall() {
rmdir_recursive("/var/tmp/stunnel");
rmdir_recursive(STUNNEL_ETCDIR);
Expand Down
21 changes: 9 additions & 12 deletions security/pfSense-pkg-stunnel/files/usr/local/pkg/stunnel.xml
Expand Up @@ -40,10 +40,6 @@
<url>/pkg.php?xml=stunnel.xml</url>
<active/>
</tab>
<tab>
<text>Certificates</text>
<url>/pkg.php?xml=stunnel_certs.xml</url>
</tab>
</tabs>
<service>
<name>stunnel</name>
Expand Down Expand Up @@ -104,11 +100,12 @@
<field>
<fielddescr>Certificate</fielddescr>
<fieldname>certificate</fieldname>
<description>Select server certificate to use for this tunnel. Certificates are defined on the 'Certificates' page.</description>
<type>select</type>
<options>
<option><name>default</name><value></value></option>
</options>
<description>Select server certificate to use for this tunnel.</description>
<type>select_source</type>
<source><![CDATA[$config['cert']]]></source>
<source_name>descr</source_name>
<source_value>refid</source_value>
<show_disable_value>default</show_disable_value>
<default_value>default</default_value>
</field>
<field>
Expand All @@ -133,13 +130,13 @@
<custom_add_php_command_late>
stunnel_save($config);
</custom_add_php_command_late>
<custom_delete_php_command>
stunnel_save($config);
</custom_delete_php_command>
<custom_php_install_command>
stunnel_install();
</custom_php_install_command>
<custom_php_deinstall_command>
stunnel_deinstall();
</custom_php_deinstall_command>
<custom_php_after_form_command>
stunnel_addcerts($config);
</custom_php_after_form_command>
</packagegui>

0 comments on commit 578946c

Please sign in to comment.