From 73fbece8f11fa253120f549e6ea837c9242534a2 Mon Sep 17 00:00:00 2001 From: mgrooms Date: Thu, 12 Mar 2009 08:02:37 +0000 Subject: [PATCH] Migrate IPsec certificate management to centralized system. --- etc/inc/config.inc | 42 ++- etc/inc/vpn.inc | 95 +++---- usr/local/www/system_certmanager.php | 21 ++ usr/local/www/vpn_ipsec.php | 1 - usr/local/www/vpn_ipsec_ca.php | 110 -------- usr/local/www/vpn_ipsec_ca_edit.php | 137 ---------- .../www/vpn_ipsec_ca_edit_create_cert.php | 243 ------------------ usr/local/www/vpn_ipsec_mobile.php | 1 - usr/local/www/vpn_ipsec_phase1.php | 82 +++--- usr/local/www/vpn_ipsec_phase2.php | 1 - 10 files changed, 132 insertions(+), 601 deletions(-) delete mode 100755 usr/local/www/vpn_ipsec_ca.php delete mode 100755 usr/local/www/vpn_ipsec_ca_edit.php delete mode 100755 usr/local/www/vpn_ipsec_ca_edit_create_cert.php diff --git a/etc/inc/config.inc b/etc/inc/config.inc index 20178af1f1..5b0ff2a048 100644 --- a/etc/inc/config.inc +++ b/etc/inc/config.inc @@ -2163,6 +2163,46 @@ endif; $config['version'] = "5.5"; } + /* Convert 5.5 -> 5.6 */ + if ($config['version'] <= 5.5) { + + /* migrate ipsec ca's to cert manager */ + if (!is_array($config['system']['ca'])) + $config['system']['ca'] = array(); + if (!is_array($config['system']['cert'])) + $config['system']['cert'] = array(); + if (is_array($config['ipsec']['cacert'])) { + foreach($config['ipsec']['cacert'], & $cacert) { + $ca = new array(); + $ca['crt'] = $cacert['cert']; + $ca['name'] = $cacert['ident']; + $config['system']['ca'][] = $ca; + } + unset($config['ipsec']['cacert']); + } + + /* migrate phase1 certificates to cert manager */ + if (is_array($config['ipsec']['phase1'])) { + foreach($config['ipsec']['phase1'], & $ph1ent) { + if($ph1ent['cert'] && $ph1ent['private-key']) { + $cert = new array(); + $cert['name'] = "IPsec Peer {$ph1ent['remote-gateway']} Certificate"; + $cert['crt'] = $ph1ent['cert']; + $cert['prv'] = $ph1ent['private-key']; + $config['system']['cert'][] = $cert; + } + if($ph1ent['cert']) + unset($ph1ent['cert']); + if($ph1ent['private-key']) + unset($ph1ent['private-key']); + if($ph1ent['peercert']) + unset($ph1ent['peercert']); + } + } + + $config['version'] = "5.6"; + } + $now = date("H:i:s"); log_error("Ended Configuration upgrade at $now"); @@ -3080,4 +3120,4 @@ function set_device_perms() { if($g['booting']) echo "."; $config = parse_config(); -?> \ No newline at end of file +?> diff --git a/etc/inc/vpn.inc b/etc/inc/vpn.inc index b9753ee519..db4b6a03ae 100644 --- a/etc/inc/vpn.inc +++ b/etc/inc/vpn.inc @@ -209,23 +209,22 @@ function vpn_ipsec_configure($ipchg = false) } /* generate CA certificates files */ - $cacertnum = 0; - if (is_array($ipseccfg['cacert']) && count($ipseccfg['cacert'])) { - foreach ($ipseccfg['cacert'] as $cacert) { - ++ $cacertnum; - if (isset ($cacert['cert'])) { - $cert = base64_decode($cacert['cert']); - $x509cert = openssl_x509_parse(openssl_x509_read($cert)); - if (is_array($x509cert) && isset ($x509cert['hash'])) { - $fd1 = fopen("{$g['varetc_path']}/{$x509cert['hash']}.0", "w"); - if (!$fd1) { - printf("Error: cannot open {$x509cert['hash']}.0 in vpn.\n"); - return 1; - } - chmod("{$g['varetc_path']}/{$x509cert['hash']}.0", 0600); - fwrite($fd1, $cert); - fclose($fd1); - } + if (is_array($config['system']['ca']) && count($config['system']['ca'])) { + foreach ($config['system']['ca'] as $ca) { + if (!isset($ca['crt'])) { + log_error("Error: Invalid certificate info for {$ca['name']}"); + continue; + } + $cert = base64_decode($ca['crt']); + $x509cert = openssl_x509_parse(openssl_x509_read($cert)); + if (!is_array($x509cert) || !isset($x509cert['hash'])) { + log_error("Error: Invalid certificate hash info for {$ca['name']}"); + continue; + } + $fname = $g['varetc_path']."/".$x509cert['hash']; + if (!file_put_contents($fname, $cert)) { + log_error("Error: Cannot write IPsec CA file for {$ca['name']}"); + continue; } } } @@ -487,52 +486,38 @@ function vpn_ipsec_configure($ipchg = false) $certline = ''; if (strstr($authmethod,'rsa')) { - if ($ph1ent['cert'] && $ph1ent['private-key']) { - $cert = base64_decode($ph1ent['cert']); - $private_key = base64_decode($ph1ent['private-key']); - } else { - /* null certificate/key */ - $cert = ''; - $private_key = ''; + + $cert = lookup_cert($ph1ent['certref']); + + if (!$cert) + { + log_error("Error: Invalid phase1 certificate reference for {$ph1ent['name']}"); + continue; } - if ($ph1ent['peercert']) - $peercert = base64_decode($ph1ent['peercert']); - else - $peercert = ''; + $certfile = "cert-".$ikeid.".crt"; + $certpath = $g['varetc_path']."/".$certfile; - $fd1 = fopen("{$g['varetc_path']}/server{$ikeid}-signed.pem", "w"); - if (!$fd1) { - printf("Error: cannot open server{$ikeid}-signed.pem in vpn.\n"); - return 1; + if (!file_put_contents($certpath, base64_decode($cert['crt']))) + { + log_error("Error: Cannot write phase1 certificate file for {$ph1ent['name']}"); + continue; } - - chmod("{$g['varetc_path']}/server{$ikeid}-signed.pem", 0600); - fwrite($fd1, $cert); - fclose($fd1); - $fd1 = fopen("{$g['varetc_path']}/server{$ikeid}-key.pem", "w"); - if (!$fd1) { - printf("Error: cannot open server{$ikeid}-key.pem in vpn.\n"); - return 1; + chmod($certpath, 0600); + + $keyfile = "cert-".$ikeid.".key"; + $keypath = $g['varetc_path']."/".$keyfile; + + if (!file_put_contents($keypath, base64_decode($cert['crt']))) + { + log_error("Error: Cannot write phase1 key file for {$ph1ent['name']}"); + continue; } - chmod("{$g['varetc_path']}/server{$ikeid}-key.pem", 0600); - fwrite($fd1, $private_key); - fclose($fd1); - $certline = "certificate_type x509 \"server{$ikeid}-signed.pem\" \"server{$ikeid}-key.pem\";"; + chmod($keypath, 0600); - if ($peercert != '') { - $fd1 = fopen("{$g['varetc_path']}/peer{$ikeid}-signed.pem", "w"); - if (!$fd1) { - printf("Error: cannot open server{$ikeid}-signed.pem in vpn.\n"); - return 1; - } - chmod("{$g['varetc_path']}/peer{$ikeid}-signed.pem", 0600); - fwrite($fd1, $peercert); - fclose($fd1); - $certline .="peers_certfile \"peer{$ikeid}-signed.pem\""; - } + $certline = "certificate_type x509 \"{$certpath}\" \"{$keypath}.key\";"; } $ealgos = ''; diff --git a/usr/local/www/system_certmanager.php b/usr/local/www/system_certmanager.php index 2e4b9e7f1f..dc58aedc9f 100644 --- a/usr/local/www/system_certmanager.php +++ b/usr/local/www/system_certmanager.php @@ -106,6 +106,24 @@ if ($act == "exp") { exit; } +if ($act == "key") { + + if (!$a_cert[$id]) { + pfSenseHeader("system_certmanager.php"); + exit; + } + + $exp_name = urlencode("{$a_cert[$id]['name']}.key"); + $exp_data = base64_decode($a_cert[$id]['prv']); + $exp_size = strlen($exp_data); + + header("Content-Type: application/octet-stream"); + header("Content-Disposition: attachment; filename={$exp_name}"); + header("Content-Length: $exp_size"); + echo $exp_data; + exit; +} + if ($act == "csr") { if (!$a_cert[$id]) { @@ -722,6 +740,9 @@ function internalca_change() { export ca + + export ca + ')"> delete cert diff --git a/usr/local/www/vpn_ipsec.php b/usr/local/www/vpn_ipsec.php index ce240a045a..44efa5ad62 100755 --- a/usr/local/www/vpn_ipsec.php +++ b/usr/local/www/vpn_ipsec.php @@ -146,7 +146,6 @@ include("head.inc"); $tab_array = array(); $tab_array[0] = array("Tunnels", true, "vpn_ipsec.php"); $tab_array[1] = array("Mobile clients", false, "vpn_ipsec_mobile.php"); - $tab_array[2] = array("CAs", false, "vpn_ipsec_ca.php"); display_top_tabs($tab_array); ?> diff --git a/usr/local/www/vpn_ipsec_ca.php b/usr/local/www/vpn_ipsec_ca.php deleted file mode 100755 index 76f53991d8..0000000000 --- a/usr/local/www/vpn_ipsec_ca.php +++ /dev/null @@ -1,110 +0,0 @@ -. - 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. -*/ - -##|+PRIV -##|*IDENT=page-vpn-ipsec-certificateauthority -##|*NAME=VPN: IPsec: Certificate Authority page -##|*DESCR=Allow access to the 'VPN: IPsec: Certificate Authority' page. -##|*MATCH=vpn_ipsec_ca.php* -##|-PRIV - - -require("guiconfig.inc"); - -if (!is_array($config['ipsec']['cacert'])) { - $config['ipsec']['cacert'] = array(); -} -ipsec_ca_sort(); -$a_secret = &$config['ipsec']['cacert']; - -if ($_GET['act'] == "del") { - if ($a_secret[$_GET['id']]) { - unset($a_secret[$_GET['id']]); - write_config(); - touch($d_ipsecconfdirty_path); - header("Location: vpn_ipsec_ca.php"); - exit; - } -} - -$pgtitle = array("VPN","IPsec","Certificate Authority"); -include("head.inc"); - -?> - - - -
-You must apply the changes in order for them to take effect."); -?> - - - - - -
- -
-
- - - - - - - - - - - - - - - -
Identifier
- - -  
-
-
-
- - - diff --git a/usr/local/www/vpn_ipsec_ca_edit.php b/usr/local/www/vpn_ipsec_ca_edit.php deleted file mode 100755 index 814e153ba9..0000000000 --- a/usr/local/www/vpn_ipsec_ca_edit.php +++ /dev/null @@ -1,137 +0,0 @@ -. - 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. -*/ - -##|+PRIV -##|*IDENT=page-vpn-ipsec-certificateauthority-edit -##|*NAME=VPN: IPsec: Certificate Authority: Edit page -##|*DESCR=Allow access to the 'VPN: IPsec: Certificate Authority: Edit' page. -##|*MATCH=vpn_ipsec_ca_edit.php* -##|-PRIV - - -require("guiconfig.inc"); - -if (!is_array($config['ipsec']['cacert'])) { - $config['ipsec']['cacert'] = array(); -} -ipsec_ca_sort(); -$a_secret = &$config['ipsec']['cacert']; - -$id = $_GET['id']; -if (isset($_POST['id'])) - $id = $_POST['id']; - -if (isset($id) && $a_secret[$id]) { - $pconfig['ident'] = $a_secret[$id]['ident']; - $pconfig['cert'] = base64_decode($a_secret[$id]['cert']); -} - -if ($_POST) { - - unset($input_errors); - $pconfig = $_POST; - - /* input validation */ - $reqdfields = explode(" ", "ident cert"); - $reqdfieldsn = explode(",", "Identifier,CA Certificate"); - if (!strstr($_POST['cert'], "BEGIN CERTIFICATE") || !strstr($_POST['cert'], "END CERTIFICATE")) - $input_errors[] = "This certificate does not appear to be valid."; - - do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors); - - if (preg_match("/[^a-zA-Z0-9@\.\-]/", $_POST['ident'])) - $input_errors[] = "The identifier contains invalid characters."; - - if (!$input_errors && !(isset($id) && $a_secret[$id])) { - /* make sure there are no dupes */ - foreach ($a_secret as $secretent) { - if ($secretent['ident'] == $_POST['ident']) { - $input_errors[] = "Another entry with the same identifier already exists."; - break; - } - } - } - - if (!$input_errors) { - - if (isset($id) && $a_secret[$id]) - $secretent = $a_secret[$id]; - - $secretent['ident'] = $_POST['ident']; - $secretent['cert'] = base64_encode($_POST['cert']); - - if (isset($id) && $a_secret[$id]) - $a_secret[$id] = $secretent; - else - $a_secret[] = $secretent; - - write_config(); - touch($d_ipsecconfdirty_path); - - header("Location: vpn_ipsec_ca.php"); - exit; - } -} - -$pgtitle = array("VPN","IPsec","Certificate Authority","Edit"); -include("head.inc"); - -?> - - - - -
- - - - - - - - - - - - - -
Identifier - -
This can be any text to describe the certificate authority. -
Certificate - -
Paste a CA certificate in X.509 PEM format here. Create Certificates
  - - - - -
-
- diff --git a/usr/local/www/vpn_ipsec_ca_edit_create_cert.php b/usr/local/www/vpn_ipsec_ca_edit_create_cert.php deleted file mode 100755 index 8b86bb9a49..0000000000 --- a/usr/local/www/vpn_ipsec_ca_edit_create_cert.php +++ /dev/null @@ -1,243 +0,0 @@ - - - -
- -

- One moment please... -

- cacert.pem'); - //mwexec('cd /tmp/ && /usr/bin/openssl x509 -in cert.csr -out cert.pem -req -signkey cakey.pem'); - $fd = fopen('/tmp/cacert.pem', 'r'); - $cacert = fread($fd, 8096); - fclose($fd); - $fd = fopen('/tmp/cakey.pem', 'r'); - $cakey = fread($fd, 8096); - fclose($fd); - $cacertA = ereg_replace("\r", '', $cacert); - $cakeyA = ereg_replace("\r", '', $cakey); - $cacert = ereg_replace("\n", '\n', $cacert); - $cakey = ereg_replace("\n", '\n', $cakey); -?> - - -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Country Code (2 Letters)
State or Province name
City name
Organization name
Organization department
Common Name (Your name)
 
-
- - - - diff --git a/usr/local/www/vpn_ipsec_mobile.php b/usr/local/www/vpn_ipsec_mobile.php index fc0fbaaefa..47ac3a3aed 100755 --- a/usr/local/www/vpn_ipsec_mobile.php +++ b/usr/local/www/vpn_ipsec_mobile.php @@ -305,7 +305,6 @@ function login_banner_change() { $tab_array = array(); $tab_array[0] = array("Tunnels", false, "vpn_ipsec.php"); $tab_array[1] = array("Mobile clients", true, "vpn_ipsec_mobile.php"); - $tab_array[2] = array("CAs", false, "vpn_ipsec_ca.php"); display_top_tabs($tab_array); ?> diff --git a/usr/local/www/vpn_ipsec_phase1.php b/usr/local/www/vpn_ipsec_phase1.php index a47d90d7a2..174f884c6d 100644 --- a/usr/local/www/vpn_ipsec_phase1.php +++ b/usr/local/www/vpn_ipsec_phase1.php @@ -95,9 +95,7 @@ if (isset($p1index) && $a_phase1[$p1index]) ($pconfig['authentication_method'] == "xauth_psk_server")) { $pconfig['pskey'] = $a_phase1[$p1index]['pre-shared-key']; } else { - $pconfig['cert'] = base64_decode($a_phase1[$p1index]['cert']); - $pconfig['peercert'] = base64_decode($a_phase1[$p1index]['peercert']); - $pconfig['privatekey'] = base64_decode($a_phase1[$p1index]['private-key']); + $pconfig['certref'] = $a_phase1[$p1index]['certref']; } $pconfig['descr'] = $a_phase1[$p1index]['descr']; @@ -146,13 +144,9 @@ if ($_POST) { if (($method == "pre_shared_key")||($method == "xauth_psk_server")) { $reqdfields = explode(" ", "pskey"); $reqdfieldsn = explode(",", "Pre-Shared Key"); - } else { - if (!strstr($pconfig['cert'], "BEGIN CERTIFICATE") || !strstr($pconfig['cert'], "END CERTIFICATE")) - $input_errors[] = "This certificate does not appear to be valid."; - if (!strstr($pconfig['privatekey'], "BEGIN RSA PRIVATE KEY") || !strstr($pconfig['privatekey'], "END RSA PRIVATE KEY")) - $input_errors[] = "This key does not appear to be valid."; - if ($pconfig['peercert']!="" && (!strstr($pconfig['peercert'], "BEGIN CERTIFICATE") || !strstr($pconfig['peercert'], "END CERTIFICATE"))) - $input_errors[] = "This peer certificate does not appear to be valid."; + } else { + $reqdfields = explode(" ", "certref"); + $reqdfieldsn = explode(",", "My Certificate"); } if (!$pconfig['mobile']) { $reqdfields[] = "remotegw"; @@ -297,8 +291,7 @@ if ($_POST) { $ph1ent['lifetime'] = $pconfig['lifetime']; $ph1ent['pre-shared-key'] = $pconfig['pskey']; $ph1ent['private-key'] = base64_encode($pconfig['privatekey']); - $ph1ent['cert'] = base64_encode($pconfig['cert']); - $ph1ent['peercert'] = base64_encode($pconfig['peercert']); + $ph1ent['certref'] = $pconfig['certref']; $ph1ent['authentication_method'] = $pconfig['authentication_method']; $ph1ent['descr'] = $pconfig['descr']; @@ -378,22 +371,16 @@ function methodsel_change() { switch (value) { case 'hybrid_rsa_server': document.getElementById('opt_psk').style.display = 'none'; - document.getElementById('opt_my_cert').style.display = ''; - document.getElementById('opt_my_pkey').style.display = ''; - document.getElementById('opt_peer_cert').style.display = 'none'; + document.getElementById('opt_cert').style.display = ''; break; case 'xauth_rsa_server': case 'rsasig': document.getElementById('opt_psk').style.display = 'none'; - document.getElementById('opt_my_cert').style.display = ''; - document.getElementById('opt_my_pkey').style.display = ''; - document.getElementById('opt_peer_cert').style.display = ''; + document.getElementById('opt_cert').style.display = ''; break; default: /* psk modes*/ document.getElementById('opt_psk').style.display = ''; - document.getElementById('opt_my_cert').style.display = 'none'; - document.getElementById('opt_my_pkey').style.display = 'none'; - document.getElementById('opt_peer_cert').style.display = 'none'; + document.getElementById('opt_cert').style.display = 'none'; break; } } @@ -462,7 +449,6 @@ function dpdchkbox_change() { $tab_array = array(); $tab_array[0] = array("Tunnels", true, "vpn_ipsec.php"); $tab_array[1] = array("Mobile clients", false, "vpn_ipsec_mobile.php"); - $tab_array[2] = array("CAs", false, "vpn_ipsec_ca.php"); display_top_tabs($tab_array); ?> @@ -660,9 +646,9 @@ function dpdchkbox_change() {
- - Must match the setting chosen on the remote side. - + + Must match the setting chosen on the remote side. + @@ -670,37 +656,29 @@ function dpdchkbox_change() { + +
+ Input your pre-shared key string. +
- + My Certificate - +
- Paste a certificate in X.509 PEM format here. - - - - My Private Key - - -
- Paste an RSA private key in PEM format here. - - - - Peer Certificate - - -
- Paste the peer X.509 certificate in PEM format here.
- Leave this blank if you want to use a CA certificate for identity validation. + + Select a certificate previously configured in the Certificate Manager. + @@ -740,7 +718,7 @@ function dpdchkbox_change() { retries
- Number consecutive failures allowed before disconnect. + Number of consecutive failures allowed before disconnect.
diff --git a/usr/local/www/vpn_ipsec_phase2.php b/usr/local/www/vpn_ipsec_phase2.php index b9a7cb9f24..6ca7a7a613 100644 --- a/usr/local/www/vpn_ipsec_phase2.php +++ b/usr/local/www/vpn_ipsec_phase2.php @@ -270,7 +270,6 @@ function typesel_change_remote(bits) { $tab_array = array(); $tab_array[0] = array("Tunnels", true, "vpn_ipsec.php"); $tab_array[1] = array("Mobile clients", false, "vpn_ipsec_mobile.php"); - $tab_array[2] = array("CAs", false, "vpn_ipsec_ca.php"); display_top_tabs($tab_array); ?>