diff options
author | Eirik Oeverby <ltning@anduin.net> | 2009-03-10 20:05:30 +0100 |
---|---|---|
committer | Eirik Oeverby <ltning@anduin.net> | 2009-03-10 20:05:30 +0100 |
commit | 4ac09def4160c485483bf5f62e8c48c7489fc5eb (patch) | |
tree | 0f9bba5b2df59fb5a89d587c100039a98fa78751 /config/stunnel | |
parent | 50ce5f7126734ef81239948f109ea70bdf124dec (diff) | |
download | pfsense-packages-4ac09def4160c485483bf5f62e8c48c7489fc5eb.tar.gz pfsense-packages-4ac09def4160c485483bf5f62e8c48c7489fc5eb.tar.bz2 pfsense-packages-4ac09def4160c485483bf5f62e8c48c7489fc5eb.zip |
Added certificate management
Major change which allows assigning certificates to tunnels.
Certificates are managed on a separate tab, but they must be manually
generated on another system and pasted in along with RSA keys.
Certificate status display lists status including days until expiry.
Diffstat (limited to 'config/stunnel')
-rw-r--r-- | config/stunnel/stunnel.inc | 232 | ||||
-rw-r--r-- | config/stunnel/stunnel_certs.xml | 147 |
2 files changed, 379 insertions, 0 deletions
diff --git a/config/stunnel/stunnel.inc b/config/stunnel/stunnel.inc new file mode 100644 index 00000000..62558e34 --- /dev/null +++ b/config/stunnel/stunnel.inc @@ -0,0 +1,232 @@ +<?php + +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(!openssl_x509_check_private_key(base64_decode($cert['cert_chain']), base64_decode($cert['cert_key']))) { + $_status='<font color="#AA0000"><b>Invalid key/cert!</b></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; + } +} + + +$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"> + 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"> + 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('/usr/local/etc/stunnel/'.$cert['filename'].'pem'); + unlink_if_exists('/usr/local/etc/stunnel/'.$cert['filename'].'key'); + unlink_if_exists('/usr/local/etc/stunnel/'.$cert['filename'].'chain'); + } +} + +function stunnel_save($config) { + $GLOBALS['config']['installedpackages']['stunnelcerts']['savemsg']=''; + conf_mount_rw(); + config_lock(); + $fout = fopen("/usr/local/etc/stunnel/stunnel.conf","w"); + fwrite($fout, "cert = /usr/local/etc/stunnel/stunnel.pem \n"); + fwrite($fout, "chroot = /var/tmp/stunnel \n"); + fwrite($fout, "setuid = stunnel \n"); + fwrite($fout, "setgid = stunnel \n"); + foreach($config['installedpackages']['stunnel']['config'] as $pkgconfig) { + fwrite($fout, "\n[" . $pkgconfig['description'] . "]\n"); + if($pkgconfig['certificate']) { + if(file_exists('/usr/local/etc/stunnel/'.$pkgconfig['certificate'].'.key') and + file_exists('/usr/local/etc/stunnel/'.$pkgconfig['certificate'].'.chain')) { + fwrite($fout, "key = /usr/local/etc/stunnel/" . $pkgconfig['certificate'] . ".key\n"); + fwrite($fout, "cert = /usr/local/etc/stunnel/" . $pkgconfig['certificate'] . ".chain\n"); + } + } + if($pkgconfig['sourceip']) fwrite($fout, "local = " . $pkgconfig['sourceip'] . "\n"); + fwrite($fout, "accept = " . $pkgconfig['localip'] . ":" . $pkgconfig['localport'] . "\n"); + fwrite($fout, "connect = " . $pkgconfig['redirectip'] . ":" . $pkgconfig['redirectport'] . "\n"); + fwrite($fout, "TIMEOUTclose = 0\n\n"); + } + fclose($fout); + conf_mount_ro(); + config_unlock(); + system("/usr/local/etc/rc.d/stunnel.sh stop 2>/dev/null"); + system("/usr/local/etc/rc.d/stunnel.sh start 2>/dev/null"); +} +function stunnel_save_cert($config) { + $GLOBALS['config']['installedpackages']['stunnelcerts']['savemsg']=''; + if(isset($_POST['id'])) { +# echo "<pre>"; +# print_r($_POST); +# echo "</pre>"; + + 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']); +# echo("<pre>"); +# print_r($_cert); +# echo("</pre>"); + if($_cert['hash']) { + if(openssl_x509_check_private_key($_POST['cert_chain'], $_POST['cert_key'])) { + file_put_contents('/usr/local/etc/stunnel/'.$_cert['hash'].'.key', + $_POST['cert_key']); + file_put_contents('/usr/local/etc/stunnel/'.$_cert['hash'].'.chain', + $_POST['cert_chain']); + file_put_contents('/usr/local/etc/stunnel/'.$_cert['hash'].'.pem', + $_POST['cert_key']."\n".$_POST['cert_chain']); + system('chown stunnel:stunnel /usr/local/etc/stunnel/*'); + chmod('/usr/local/etc/stunnel/'.$_cert['hash'].'.key', 0600); + chmod('/usr/local/etc/stunnel/'.$_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('/usr/local/etc/stunnel/'.$_fname.'.chain'); + unlink_if_exists('/usr/local/etc/stunnel/'.$_fname.'.key'); + unlink_if_exists('/usr/local/etc/stunnel/'.$_fname.'.pem'); + } + } +} + +function stunnel_install() { + safe_mkdir("/usr/local/etc/stunnel"); + system("/usr/bin/openssl req -new -x509 -days 365 -nodes -out /usr/local/etc/stunnel/stunnel.pem -keyout /usr/local/etc/stunnel/stunnel.pem 2>/dev/null"); + chmod("/usr/local/etc/stunnel/stunnel.pem", 0600); + make_dirs("/var/tmp/stunnel/var/tmp/run/stunnel"); + system("/usr/sbin/chown -R stunnel:stunnel /var/tmp/stunnel"); + $_rcfile['file']='stunnel.sh'; + $_rcfile['start'].="/usr/local/bin/stunnel /usr/local/etc/stunnel/stunnel.conf \n\t"; + $_rcfile['stop'].="killall stunnel \n\t"; + write_rcfile($_rcfile); + unlink_if_exists("/usr/local/etc/rc.d/stunnel"); + + conf_mount_rw(); + config_lock(); + $fout = fopen("/usr/local/etc/stunnel/stunnel.conf","w"); + fwrite($fout, "cert = /usr/local/etc/stunnel/stunnel.pem \n"); + fwrite($fout, "chroot = /var/tmp/stunnel \n"); + fwrite($fout, "setuid = stunnel \n"); + fwrite($fout, "setgid = stunnel \n"); + foreach($config['installedpackages']['stunnel']['config'] as $pkgconfig) { + fwrite($fout, "\n[" . $pkgconfig['description'] . "]\n"); + if($pkgconfig['sourceip']) fwrite($fout, "local = " . $pkgconfig['sourceip'] . "\n"); + fwrite($fout, "accept = " . $pkgconfig['localip'] . ":" . $pkgconfig['localport'] . "\n"); + fwrite($fout, "connect = " . $pkgconfig['redirectip'] . ":" . $pkgconfig['redirectport'] . "\n"); + fwrite($fout, "TIMEOUTclose = 0\n\n"); + } + fclose($fout); + conf_mount_ro(); + config_unlock(); +} + +function stunnel_deinstall() { + rmdir_recursive("/var/tmp/stunnel"); + rmdir_recursive("/usr/local/etc/stunnel*"); + unlink_if_exists("/usr/local/etc/rc.d/stunnel.sh"); +} + +?>
\ No newline at end of file diff --git a/config/stunnel/stunnel_certs.xml b/config/stunnel/stunnel_certs.xml new file mode 100644 index 00000000..3d7cc3fa --- /dev/null +++ b/config/stunnel/stunnel_certs.xml @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?> +<packagegui> + <copyright> + <![CDATA[ +/* $Id$ */ +/* ========================================================================== */ +/* + stunnel.xml + part of pfSense (http://www.pfSense.com) + Copyright (C) 2007-2008 Scott Ullrich + All rights reserved. + */ +/* ========================================================================== */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ +/* ========================================================================== */ + ]]> + </copyright> + <description>Stunnel certificates</description> + <requirements>Describe your package requirements here</requirements> + <faq>Currently there are no FAQ items provided.</faq> + <name>stunnelcerts</name> + <version>4.18</version> + <title>Services: Secure Tunnel - Certificates</title> + <!-- configpath gets expanded out automatically and config items will be + stored in that location --> + <configpath>['installedpackages']['package']['$packagename']['configuration']</configpath> + + <tabs> + <tab> + <text>Tunnels</text> + <url>/pkg.php?xml=stunnel.xml</url> + </tab> + <tab> + <text>Certificates</text> + <url>/pkg.php?xml=stunnel_certs.xml</url> + <active/> + </tab> + </tabs> + + <!-- adddeleteeditpagefields items will appear on the first page where you can add / delete or edit + items. An example of this would be the nat page where you add new nat redirects --> + <adddeleteeditpagefields> + <columnitem> + <fielddescr>Description</fielddescr> + <fieldname>description</fieldname> + </columnitem> + <columnitem> + <fielddescr>Subject</fielddescr> + <fieldname>subject</fieldname> + </columnitem> +<!-- <columnitem> + <fielddescr>Valid until</fielddescr> + <fieldname>expiry</fieldname> + </columnitem> --> + <columnitem> + <fielddescr>Status</fielddescr> + <fieldname>status</fieldname> + </columnitem> + + </adddeleteeditpagefields> + <!-- fields gets invoked when the user adds or edits a item. the following items + will be parsed and rendered for the user as a gui with input, and selectboxes. --> + <fields> + <field> + <fielddescr>Description</fielddescr> + <fieldname>description</fieldname> + <description>Enter a (short) description for this certificate</description> + <type>input</type> + </field> + <field> + <fielddescr>Certificate filename</fielddescr> + <fieldname>filename</fieldname> + <description>File name of certificate (read-only; updated on save). Extensions (.pem, .chain, .key) are added automatically.</description> + <type>input</type> + </field> + <field> + <fielddescr>Certificate subject</fielddescr> + <fieldname>subject</fieldname> + <description>Certificate subject (read-only; updated on save)</description> + <type>input</type> + <size>50</size> + </field> + <field> + <fielddescr>Certificate valid until</fielddescr> + <fieldname>expiry</fieldname> + <description>The certificate will expire on this date, and will no longer work.</description> + <type>input</type> + </field> + <field> + <fielddescr>RSA private key</fielddescr> + <fieldname>cert_key</fieldname> + <description>RSA private key used for certificate. Do not change for existing certificates!<br> + <b>Leave blank to automatically create key and certificate signing request on save.</b></description> + <type>textarea</type> + <rows>7</rows> + <cols>65</cols> + </field> + <field> + <fielddescr>Certificate chain</fielddescr> + <fieldname>cert_chain</fieldname> + <description>Full certificate chain; root certificate on top, then any intermediates, server certificate at the end.<br> + <b>Full chain required for private or EV certificates!</b></description> + <type>textarea</type> + <rows>7</rows> + <cols>65</cols> + </field> + </fields> + + <include_file>/usr/local/pkg/stunnel.inc</include_file> + <custom_add_php_command> + stunnel_save_cert($config); + stunnel_save($config); + </custom_add_php_command> + <custom_php_command_before_form> + stunnel_printcsr(); + </custom_php_command_before_form> + <custom_php_after_form_command> + stunnel_disablefields(); + </custom_php_after_form_command> + <custom_delete_php_command> + stunnel_delete($config); + </custom_delete_php_command> + +</packagegui> |