mirror of
https://github.com/lucaspalomodevelop/core.git
synced 2026-03-13 08:09:41 +00:00
Merge branch 'ppmathis-feature/ipsec-pubkey-auth'
This commit is contained in:
commit
6b542e91d0
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Pascal Mathis <mail@pascalmathis.com>
|
||||
* Copyright (C) 2016 Deciso B.V.
|
||||
* Copyright (C) 2008 Shrew Soft Inc. <mgrooms@shrew.net>
|
||||
* Copyright (C) 2008 Ermal Luçi
|
||||
@ -86,6 +87,7 @@ function ipsec_p1_authentication_methods()
|
||||
'rsa_eap-mschapv2' => array( 'name' => 'Mutual RSA + EAP-MSCHAPV2', 'mobile' => true),
|
||||
'eap-radius' => array( 'name' => 'EAP-RADIUS', 'mobile' => true),
|
||||
'rsasig' => array( 'name' => 'Mutual RSA', 'mobile' => false ),
|
||||
'pubkey' => array( 'name' => 'Mutual Public Key', 'mobile' => false ),
|
||||
'pre_shared_key' => array( 'name' => 'Mutual PSK', 'mobile' => false ),
|
||||
);
|
||||
}
|
||||
@ -542,6 +544,14 @@ function ipsec_mobilekey_sort()
|
||||
});
|
||||
}
|
||||
|
||||
function ipsec_lookup_keypair($uuid)
|
||||
{
|
||||
$mdl = new \OPNsense\IPsec\IPsec();
|
||||
$node = $mdl->getNodeByReference('keyPairs.keyPair.' . $uuid);
|
||||
|
||||
return $node ? $node->getNodes() : null;
|
||||
}
|
||||
|
||||
function ipsec_get_number_of_phase2($ikeid)
|
||||
{
|
||||
global $config;
|
||||
@ -791,14 +801,16 @@ function ipsec_configure_do($verbose = false, $interface = '')
|
||||
} else {
|
||||
$certpath = "/usr/local/etc/ipsec.d/certs";
|
||||
$capath = "/usr/local/etc/ipsec.d/cacerts";
|
||||
$keypath = "/usr/local/etc/ipsec.d/private";
|
||||
$publickeypath = "/usr/local/etc/ipsec.d/public";
|
||||
$privatekeypath = "/usr/local/etc/ipsec.d/private";
|
||||
|
||||
mwexec("/sbin/ifconfig enc0 up");
|
||||
set_single_sysctl("net.inet.ip.ipsec_in_use", "1");
|
||||
|
||||
/* needed directories for config files */
|
||||
@mkdir($capath);
|
||||
@mkdir($keypath);
|
||||
@mkdir($privatekeypath);
|
||||
@mkdir($publickeypath);
|
||||
@mkdir($certpath);
|
||||
@mkdir('/usr/local/etc/ipsec.d');
|
||||
@mkdir('/usr/local/etc/ipsec.d/crls');
|
||||
@ -1093,7 +1105,7 @@ function ipsec_configure_do($verbose = false, $interface = '')
|
||||
|
||||
@chmod($certpath, 0600);
|
||||
|
||||
$ph1keyfile = "{$keypath}/cert-{$ph1ent['ikeid']}.key";
|
||||
$ph1keyfile = "{$privatekeypath}/cert-{$ph1ent['ikeid']}.key";
|
||||
if (!file_put_contents($ph1keyfile, base64_decode($cert['prv']))) {
|
||||
log_error(sprintf('Error: Cannot write phase1 key file for %s', $ph1ent['name']));
|
||||
continue;
|
||||
@ -1120,6 +1132,59 @@ function ipsec_configure_do($verbose = false, $interface = '')
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate files for key pairs (e.g. RSA) */
|
||||
foreach ($a_phase1 as $ph1ent) {
|
||||
if(isset($ph1ent['disabled'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!empty($ph1ent['local-kpref'])) {
|
||||
$keyPair = ipsec_lookup_keypair($ph1ent['local-kpref']);
|
||||
if (!$keyPair || empty($keyPair['publicKey']) || empty($keyPair['privateKey'])) {
|
||||
log_error(sprintf('Error: Invalid phase1 local key pair reference for %s', $ph1ent['name']));
|
||||
continue;
|
||||
}
|
||||
|
||||
@chmod($publickeypath, 0600);
|
||||
|
||||
$ph1publickeyfile = "${publickeypath}/publickey-local-{$ph1ent['ikeid']}.pem";
|
||||
if (!file_put_contents($ph1publickeyfile, $keyPair['publicKey'])) {
|
||||
log_error(sprintf('Error: Cannot write phase1 local public key file for %s', $ph1ent['name']));
|
||||
@unlink($ph1publickeyfile);
|
||||
continue;
|
||||
}
|
||||
@chmod($ph1publickeyfile, 0600);
|
||||
|
||||
$ph1privatekeyfile = "${privatekeypath}/privatekey-local-{$ph1ent['ikeid']}.pem";
|
||||
if (!file_put_contents($ph1privatekeyfile, $keyPair['privateKey'])) {
|
||||
log_error(sprintf('Error: Cannot write phase1 local private key file for %s', $ph1ent['name']));
|
||||
@unlink($ph1privatekeyfile);
|
||||
continue;
|
||||
}
|
||||
@chmod($ph1privatekeyfile, 0600);
|
||||
|
||||
$pskconf .= " : RSA {$ph1privatekeyfile}\n";
|
||||
}
|
||||
|
||||
if (!empty($ph1ent['peer-kpref'])) {
|
||||
$keyPair = ipsec_lookup_keypair($ph1ent['peer-kpref']);
|
||||
if (!$keyPair || empty($keyPair['publicKey'])) {
|
||||
log_error(sprintf('Error: Invalid phase1 peer key pair reference for %s', $ph1ent['name']));
|
||||
continue;
|
||||
}
|
||||
|
||||
@chmod($publickeypath, 0600);
|
||||
|
||||
$ph1publickeyfile = "${publickeypath}/publickey-peer-{$ph1ent['ikeid']}.pem";
|
||||
if (!file_put_contents($ph1publickeyfile, $keyPair['publicKey'])) {
|
||||
log_error(sprintf('Error: Cannot write phase1 peer public key file for %s', $ph1ent['name']));
|
||||
@unlink($ph1publickeyfile);
|
||||
continue;
|
||||
}
|
||||
@chmod($ph1publickeyfile, 0600);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add user PSKs */
|
||||
if (isset($config['system']['user']) && is_array($config['system']['user'])) {
|
||||
foreach ($config['system']['user'] as $user) {
|
||||
@ -1289,12 +1354,14 @@ function ipsec_configure_do($verbose = false, $interface = '')
|
||||
$authentication = "leftauth = psk\n\trightauth = psk";
|
||||
break;
|
||||
case 'rsasig':
|
||||
case 'pubkey':
|
||||
$authentication = "leftauth = pubkey\n\trightauth = pubkey";
|
||||
break;
|
||||
case 'hybrid_rsa_server':
|
||||
$authentication = "leftauth = pubkey\n\trightauth = xauth";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($ph1ent['certref'])) {
|
||||
$authentication .= "\n\tleftcert = {$certpath}/cert-{$ph1ent['ikeid']}.crt";
|
||||
$authentication .= "\n\tleftsendcert = always";
|
||||
@ -1309,8 +1376,15 @@ function ipsec_configure_do($verbose = false, $interface = '')
|
||||
$authentication .= "\n\trightca = \"/$rightca\"";
|
||||
}
|
||||
}
|
||||
$left_spec = $ep;
|
||||
|
||||
if (!empty($ph1ent['local-kpref'])) {
|
||||
$authentication .= "\n\tleftsigkey = {$publickeypath}/publickey-local-{$ph1ent['ikeid']}.pem";
|
||||
}
|
||||
if (!empty($ph1ent['peer-kpref'])) {
|
||||
$authentication .= "\n\trightsigkey = {$publickeypath}/publickey-peer-{$ph1ent['ikeid']}.pem";
|
||||
}
|
||||
|
||||
$left_spec = $ep;
|
||||
if (isset($ph1ent['reauth_enable'])) {
|
||||
$reauth = "reauth = no";
|
||||
} else {
|
||||
|
||||
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2019 Pascal Mathis <mail@pascalmathis.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\IPsec\Api;
|
||||
|
||||
use OPNsense\Base\ApiMutableModelControllerBase;
|
||||
|
||||
/**
|
||||
* Class KeyPairsController
|
||||
* @package OPNsense\IPsec\Api
|
||||
*/
|
||||
class KeyPairsController extends ApiMutableModelControllerBase
|
||||
{
|
||||
protected static $internalModelName = 'ipsec';
|
||||
protected static $internalModelClass = 'OPNsense\IPsec\IPsec';
|
||||
|
||||
/**
|
||||
* Search key pairs
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function searchItemAction()
|
||||
{
|
||||
return $this->searchBase(
|
||||
'keyPairs.keyPair',
|
||||
['name', 'keyType', 'keySize', 'keyFingerprint']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update key pair with given properties
|
||||
* @param $uuid
|
||||
* @return array
|
||||
* @throws \OPNsense\Base\UserException
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function setItemAction($uuid = null)
|
||||
{
|
||||
$response = $this->setBase('keyPair', 'keyPairs.keyPair', $uuid);
|
||||
if (!empty($response['result']) && $response['result'] === 'saved') {
|
||||
touch('/tmp/ipsec.dirty'); // mark_subsystem_dirty('ipsec')
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new key pair with given properties
|
||||
* @return array
|
||||
* @throws \OPNsense\Base\UserException
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function addItemAction()
|
||||
{
|
||||
$response = $this->addBase('keyPair', 'keyPairs.keyPair');
|
||||
if (!empty($response['result']) && $response['result'] === 'saved') {
|
||||
touch('/tmp/ipsec.dirty'); // mark_subsystem_dirty('ipsec')
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve key pair or return defaults for new one
|
||||
* @param $uuid
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function getItemAction($uuid = null)
|
||||
{
|
||||
return $this->getBase('keyPair', 'keyPairs.keyPair', $uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete key pair by UUID
|
||||
* @param $uuid
|
||||
* @return array
|
||||
* @throws \OPNsense\Base\UserException
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function delItemAction($uuid)
|
||||
{
|
||||
$response = $this->delBase('keyPairs.keyPair', $uuid);
|
||||
if (!empty($response['result']) && $response['result'] === 'deleted') {
|
||||
touch('/tmp/ipsec.dirty'); // mark_subsystem_dirty('ipsec')
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2019 Pascal Mathis <mail@pascalmathis.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\IPsec\Api;
|
||||
|
||||
use OPNsense\Base\ApiControllerBase;
|
||||
use OPNsense\Core\Backend;
|
||||
|
||||
/**
|
||||
* Class LegacySubsystemController
|
||||
* @package OPNsense\IPsec\Api
|
||||
*/
|
||||
class LegacySubsystemController extends ApiControllerBase
|
||||
{
|
||||
/**
|
||||
* Returns the status of the legacy subsystem, which currently only includes a boolean specifying if the subsystem
|
||||
* is marked as dirty, which means that there are pending changes.
|
||||
* @return array
|
||||
*/
|
||||
public function statusAction()
|
||||
{
|
||||
return [
|
||||
'isDirty' => file_exists('/tmp/ipsec.dirty') // is_subsystem_dirty('ipsec')
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the IPsec configuration using the legacy subsystem and return a message describing the result
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function applyConfigAction()
|
||||
{
|
||||
try {
|
||||
if (!$this->request->isPost())
|
||||
throw new \Exception(gettext('Request method not allowed, expected POST'));
|
||||
|
||||
$backend = new Backend();
|
||||
$bckresult = trim($backend->configdRun('ipsec reconfigure'));
|
||||
if ($bckresult !== 'OK')
|
||||
throw new \Exception($bckresult);
|
||||
|
||||
// clear_subsystem_dirty('ipsec')
|
||||
if (!@unlink('/tmp/ipsec.dirty'))
|
||||
throw new \Exception(gettext('Could not remove /tmp/ipsec.dirty to mark subsystem as clean'));
|
||||
|
||||
return ['message' => gettext('The changes have been applied successfully.')];
|
||||
} catch (\Exception $e) {
|
||||
throw new \Exception(sprintf(
|
||||
gettext('Unable to apply IPsec subsystem configuration: %s'),
|
||||
$e->getMessage()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2019 Pascal Mathis <mail@pascalmathis.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\IPsec;
|
||||
|
||||
/**
|
||||
* Class KeyPairsController
|
||||
* @package OPNsense\IPsec
|
||||
*/
|
||||
class KeyPairsController extends \OPNsense\Base\IndexController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->formDialogKeyPair = $this->getForm('dialogKeyPair');
|
||||
$this->view->pick('OPNsense/IPsec/key_pairs');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>keyPair.name</id>
|
||||
<label>Name</label>
|
||||
<type>text</type>
|
||||
<help>Enter a name for this key pair. The name should help you to identify this key pair.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>keyPair.keyType</id>
|
||||
<label>Key Type</label>
|
||||
<type>dropdown</type>
|
||||
<help>Select the type of the key pair. Currently RSA is the only supported type.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>keyPair.publicKey</id>
|
||||
<label>Public Key</label>
|
||||
<type>textbox</type>
|
||||
<help>
|
||||
Paste a public key of the selected type in X.509 format.
|
||||
Must be pasted including the '-----BEGIN ...-----' and '-----END [...]-----' headers.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>keyPair.privateKey</id>
|
||||
<label>Private Key</label>
|
||||
<type>textbox</type>
|
||||
<help>
|
||||
Paste an optional private key of the selected type in X.509 format which belongs to the public key specified above.
|
||||
When adding the public key of a peer, this field should not be specified as the private key remains solely with the peer.
|
||||
Must be pasted including the '-----BEGIN ...-----' and '-----END [...]-----' headers.
|
||||
</help>
|
||||
</field>
|
||||
</form>
|
||||
@ -506,30 +506,6 @@
|
||||
<pattern>status_interfaces.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-interfaces>
|
||||
<page-status-ipsec>
|
||||
<name>Status: IPsec</name>
|
||||
<patterns>
|
||||
<pattern>diag_ipsec.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-ipsec>
|
||||
<page-status-ipsec-leases>
|
||||
<name>Status: IPsec: Leasespage</name>
|
||||
<patterns>
|
||||
<pattern>diag_ipsec_leases.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-ipsec-leases>
|
||||
<page-status-ipsec-sad>
|
||||
<name>Status: IPsec: SAD</name>
|
||||
<patterns>
|
||||
<pattern>diag_ipsec_sad.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-ipsec-sad>
|
||||
<page-status-ipsec-spd>
|
||||
<name>Status: IPsec: SPD</name>
|
||||
<patterns>
|
||||
<pattern>diag_ipsec_spd.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-ipsec-spd>
|
||||
<page-status-openvpn>
|
||||
<name>Status: OpenVPN</name>
|
||||
<patterns>
|
||||
@ -548,14 +524,8 @@
|
||||
<pattern>diag_logs_auth.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-systemlogs-portalauth>
|
||||
<page-status-systemlogs-ipsecvpn>
|
||||
<name>Status: System logs: IPsec VPN</name>
|
||||
<patterns>
|
||||
<pattern>diag_logs_ipsec.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-systemlogs-ipsecvpn>
|
||||
<page-status-systemlogs-ppp>
|
||||
<name>Status: System logs: IPsec VPN</name>
|
||||
<name>Status: System logs: PPP</name>
|
||||
<patterns>
|
||||
<pattern>diag_logs_ppp.php*</pattern>
|
||||
</patterns>
|
||||
@ -733,42 +703,6 @@
|
||||
<pattern>system_usermanager_passwordmg.php*</pattern>
|
||||
</patterns>
|
||||
</page-system-usermanager-passwordmg>
|
||||
<page-vpn-ipsec>
|
||||
<name>VPN: IPsec</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec>
|
||||
<page-vpn-ipsec-editphase1>
|
||||
<name>VPN: IPsec: Edit Phase 1</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec_phase1.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-editphase1>
|
||||
<page-vpn-ipsec-editphase2>
|
||||
<name>VPN: IPsec: Edit Phase 2</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec_phase2.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-editphase2>
|
||||
<page-vpn-ipsec-editkeys>
|
||||
<name>VPN: IPsec: Edit Pre-Shared Keys</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec_keys_edit.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-editkeys>
|
||||
<page-vpn-ipsec-mobile>
|
||||
<name>VPN: IPsec: Mobile</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec_mobile.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-mobile>
|
||||
<page-vpn-ipsec-listkeys>
|
||||
<name>VPN: IPsec: Pre-Shared Keys List</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec_keys.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-listkeys>
|
||||
<page-openvpn-client-export>
|
||||
<name>VPN: OpenVPN: Client Export Utility</name>
|
||||
<patterns>
|
||||
|
||||
@ -217,26 +217,6 @@
|
||||
<RouterAdv VisibleName="Router Advertisements" cssClass="fa fa-bullseye fa-fw" />
|
||||
</Services>
|
||||
<VPN order="50" cssClass="fa fa-globe">
|
||||
<IPsec cssClass="fa fa-lock fa-fw" order="10">
|
||||
<Tunnels order="10" VisibleName="Tunnel Settings" url="/vpn_ipsec.php">
|
||||
<Phase1 url="/vpn_ipsec_phase1.php*" visibility="hidden"/>
|
||||
<Phase2 url="/vpn_ipsec_phase2.php*" visibility="hidden"/>
|
||||
</Tunnels>
|
||||
<Mobile order="20" VisibleName="Mobile Clients" url="/vpn_ipsec_mobile.php">
|
||||
<Act url="/vpn_ipsec_mobile.php*" visibility="hidden"/>
|
||||
</Mobile>
|
||||
<Keys order="30" VisibleName="Pre-Shared Keys" url="/vpn_ipsec_keys.php">
|
||||
<Edit url="/vpn_ipsec_keys_edit.php*" visibility="hidden"/>
|
||||
</Keys>
|
||||
<Settings order="40" VisibleName="Advanced Settings" url="/vpn_ipsec_settings.php"/>
|
||||
<Status order="50" VisibleName="Status Overview" url="/diag_ipsec.php">
|
||||
<Act url="/diag_ipsec.php?*" visibility="hidden"/>
|
||||
</Status>
|
||||
<Leases order="60" VisibleName="Lease Status" url="/diag_ipsec_leases.php"/>
|
||||
<SAD order="70" VisibleName="Security Association Database" url="/diag_ipsec_sad.php"/>
|
||||
<SPD order="80" VisibleName="Security Policy Database" url="/diag_ipsec_spd.php"/>
|
||||
<LogFile order="90" VisibleName="Log File" url="/diag_logs_ipsec.php"/>
|
||||
</IPsec>
|
||||
<OpenVPN cssClass="fa fa-lock fa-fw" order="20">
|
||||
<Servers order="10" url="/vpn_openvpn_server.php">
|
||||
<Edit url="/vpn_openvpn_server.php?*" visibility="hidden"/>
|
||||
|
||||
80
src/opnsense/mvc/app/models/OPNsense/IPsec/ACL/ACL.xml
Normal file
80
src/opnsense/mvc/app/models/OPNsense/IPsec/ACL/ACL.xml
Normal file
@ -0,0 +1,80 @@
|
||||
<acl>
|
||||
<!-- ACLs for MVC code -->
|
||||
<page-vpn-ipsec-keypairs>
|
||||
<name>VPN: IPsec: Key Pairs</name>
|
||||
<description>Allow access to the IPsec Key Pairs</description>
|
||||
<patterns>
|
||||
<pattern>ui/ipsec/key-pairs/*</pattern>
|
||||
<pattern>api/ipsec/key-pairs/*</pattern>
|
||||
<pattern>api/ipsec/legacy-subsystem/*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-keypairs>
|
||||
|
||||
<!-- ACLs for legacy code -->
|
||||
<page-vpn-ipsec>
|
||||
<name>VPN: IPsec</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec>
|
||||
<page-vpn-ipsec-editphase1>
|
||||
<name>VPN: IPsec: Edit Phase 1</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec_phase1.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-editphase1>
|
||||
<page-vpn-ipsec-editphase2>
|
||||
<name>VPN: IPsec: Edit Phase 2</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec_phase2.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-editphase2>
|
||||
<page-vpn-ipsec-editkeys>
|
||||
<name>VPN: IPsec: Edit Pre-Shared Keys</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec_keys_edit.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-editkeys>
|
||||
<page-vpn-ipsec-mobile>
|
||||
<name>VPN: IPsec: Mobile</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec_mobile.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-mobile>
|
||||
<page-vpn-ipsec-listkeys>
|
||||
<name>VPN: IPsec: Pre-Shared Keys List</name>
|
||||
<patterns>
|
||||
<pattern>vpn_ipsec_keys.php*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-listkeys>
|
||||
<page-status-ipsec>
|
||||
<name>Status: IPsec</name>
|
||||
<patterns>
|
||||
<pattern>diag_ipsec.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-ipsec>
|
||||
<page-status-ipsec-leases>
|
||||
<name>Status: IPsec: Leasespage</name>
|
||||
<patterns>
|
||||
<pattern>diag_ipsec_leases.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-ipsec-leases>
|
||||
<page-status-ipsec-sad>
|
||||
<name>Status: IPsec: SAD</name>
|
||||
<patterns>
|
||||
<pattern>diag_ipsec_sad.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-ipsec-sad>
|
||||
<page-status-ipsec-spd>
|
||||
<name>Status: IPsec: SPD</name>
|
||||
<patterns>
|
||||
<pattern>diag_ipsec_spd.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-ipsec-spd>
|
||||
<page-status-systemlogs-ipsecvpn>
|
||||
<name>Status: System logs: IPsec VPN</name>
|
||||
<patterns>
|
||||
<pattern>diag_logs_ipsec.php*</pattern>
|
||||
</patterns>
|
||||
</page-status-systemlogs-ipsecvpn>
|
||||
</acl>
|
||||
191
src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.php
Normal file
191
src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.php
Normal file
@ -0,0 +1,191 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2019 Pascal Mathis <mail@pascalmathis.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\IPsec;
|
||||
|
||||
use OPNsense\Base\BaseModel;
|
||||
|
||||
/**
|
||||
* Class IPsec
|
||||
* @package OPNsense\IPsec
|
||||
*/
|
||||
class IPsec extends BaseModel
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function performValidation($validateFullModel = false)
|
||||
{
|
||||
$messages = parent::performValidation($validateFullModel);
|
||||
$keyPairs = [];
|
||||
|
||||
foreach ($this->getFlatNodes() as $key => $node) {
|
||||
if ($validateFullModel || $node->isFieldChanged()) {
|
||||
$tagName = $node->getInternalXMLTagName();
|
||||
$parentNode = $node->getParentNode();
|
||||
$parentKey = $parentNode->__reference;
|
||||
$parentTagName = $parentNode->getInternalXMLTagName();
|
||||
|
||||
if ($parentTagName === 'keyPair' && in_array($tagName, ['keyType', 'privateKey', 'publicKey'])) {
|
||||
$keyPairs[$parentKey] = $parentNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($keyPairs as $key => $node) {
|
||||
$this->validateKeyPair($key, $node, $messages);
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a keyPair instance within a model. This method does change the model contents by replacing the public
|
||||
* and private key contents with a sanitized representation as well as storing the key size and fingerprint.
|
||||
* @param $nodeKey string Fully-qualified key of the keyPair instance within a model
|
||||
* @param $keyPair \OPNsense\Base\FieldTypes\BaseField Field instance of a keyPair
|
||||
* @param $messages \Phalcon\Validation\Message\Group Validation message group
|
||||
*/
|
||||
private function validateKeyPair($nodeKey, $keyPair, $messages)
|
||||
{
|
||||
$publicKey = $privateKey = null;
|
||||
if (empty((string)$keyPair->keyType))
|
||||
return;
|
||||
|
||||
// Validate public key
|
||||
if (!empty((string)$keyPair->publicKey)) {
|
||||
try {
|
||||
$publicKey = $this->parseCryptographicKey(
|
||||
(string)$keyPair->publicKey,
|
||||
(string)$keyPair->keyType . '-public'
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
$messages->appendMessage(new \Phalcon\Validation\Message($e->getMessage(), $nodeKey . '.publicKey'));
|
||||
}
|
||||
}
|
||||
|
||||
// Validate private key
|
||||
if (!empty((string)$keyPair->privateKey)) {
|
||||
try {
|
||||
$privateKey = $this->parseCryptographicKey(
|
||||
(string)$keyPair->privateKey,
|
||||
(string)$keyPair->keyType . '-private'
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
$messages->appendMessage(new \Phalcon\Validation\Message($e->getMessage(), $nodeKey . '.privateKey'));
|
||||
}
|
||||
}
|
||||
|
||||
// Compare SHA1 fingerprint of public and private keys to check if they belong to each other
|
||||
if ($publicKey && $privateKey) {
|
||||
if ($publicKey['fingerprint'] !== $privateKey['fingerprint']) {
|
||||
$messages->appendMessage(new \Phalcon\Validation\Message(
|
||||
gettext('This private key does not belong to the given public key.'), $nodeKey . '.privateKey'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Store sanitized representation of keys and cache key statistics
|
||||
$keyPair->publicKey = $publicKey ? $publicKey['pem'] : (string)$keyPair->publicKey;
|
||||
$keyPair->privateKey = $privateKey ? $privateKey['pem'] : (string)$keyPair->privateKey;
|
||||
$keyPair->keySize = $publicKey ? $publicKey['size'] : 0;
|
||||
$keyPair->keyFingerprint = $publicKey ? $publicKey['fingerprint'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a cryptographic key of a given type using OpenSSL and return an array of informational data.
|
||||
* @param $keyString string
|
||||
* @param $keyType string
|
||||
* @return array
|
||||
*/
|
||||
public function parseCryptographicKey($keyString, $keyType)
|
||||
{
|
||||
// Attempt to load key with correct type
|
||||
if ($keyType === 'rsa-public') {
|
||||
$key = openssl_pkey_get_public($keyString);
|
||||
} elseif ($keyType === 'rsa-private') {
|
||||
$key = openssl_pkey_get_private($keyString);
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
gettext('Unsupported key type: %s'),
|
||||
$keyType
|
||||
));
|
||||
}
|
||||
|
||||
// Ensure that key has been successfully loaded
|
||||
if ($key === false) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
gettext('Could not load potentially invalid %s key: %s'),
|
||||
$keyType, openssl_error_string()
|
||||
));
|
||||
}
|
||||
|
||||
// Attempt to fetch key details
|
||||
$keyDetails = openssl_pkey_get_details($key);
|
||||
if ($keyDetails === false) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
gettext('Could not fetch details for %s key: %s'),
|
||||
$keyType, openssl_error_string()
|
||||
));
|
||||
}
|
||||
|
||||
// Verify given public key is valid for usage with Strongswan
|
||||
if ($keyDetails['type'] !== OPENSSL_KEYTYPE_RSA) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
gettext('Unsupported OpenSSL key type [%d] for %s key, expected RSA.'),
|
||||
$keyDetails['type'], $keyType
|
||||
));
|
||||
}
|
||||
|
||||
// Fetch sanitized PEM representation of key
|
||||
if ($keyType === 'rsa-private') {
|
||||
if (!openssl_pkey_export($key, $keySanitized, null)) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
gettext('Could not generate sanitized %s key in PEM format: %s'),
|
||||
$keyType, openssl_error_string()
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$keySanitized = $keyDetails['key'];
|
||||
}
|
||||
|
||||
// Calculate fingerprint for the public key (when a private key was given, its public key is calculated)
|
||||
$keyUnwrapped = trim(preg_replace('/\\+s/', '', preg_replace(
|
||||
'~^-----BEGIN(?:[A-Z]+ )? PUBLIC KEY-----([A-Za-z0-9+/=\\s]+)-----END(?:[A-Z]+ )? PUBLIC KEY-----$~m',
|
||||
'\\1', $keyDetails['key']
|
||||
)));
|
||||
$keyFingerprint = substr(chunk_split(hash('sha1', base64_decode($keyUnwrapped)), 2, ':'), 0, -1);
|
||||
|
||||
return [
|
||||
'resource' => $key,
|
||||
'size' => $keyDetails['bits'],
|
||||
'fingerprint' => $keyFingerprint,
|
||||
'type' => $keyType,
|
||||
'pem' => $keySanitized
|
||||
];
|
||||
}
|
||||
}
|
||||
30
src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.xml
Normal file
30
src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<model>
|
||||
<mount>//OPNsense/IPsec</mount>
|
||||
<description>
|
||||
OPNsense IPsec
|
||||
</description>
|
||||
<items>
|
||||
<keyPairs>
|
||||
<keyPair type="ArrayField">
|
||||
<name type="TextField">
|
||||
<Required>Y</Required>
|
||||
</name>
|
||||
<keyType type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>rsa</default>
|
||||
<OptionValues>
|
||||
<rsa>RSA</rsa>
|
||||
</OptionValues>
|
||||
</keyType>
|
||||
<publicKey type="TextField">
|
||||
<Required>Y</Required>
|
||||
</publicKey>
|
||||
<privateKey type="TextField">
|
||||
<Required>N</Required>
|
||||
</privateKey>
|
||||
<keySize type="IntegerField"/>
|
||||
<keyFingerprint type="TextField"/>
|
||||
</keyPair>
|
||||
</keyPairs>
|
||||
</items>
|
||||
</model>
|
||||
25
src/opnsense/mvc/app/models/OPNsense/IPsec/Menu/Menu.xml
Normal file
25
src/opnsense/mvc/app/models/OPNsense/IPsec/Menu/Menu.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<menu>
|
||||
<VPN>
|
||||
<IPsec cssClass="fa fa-lock fa-fw" order="10">
|
||||
<Tunnels order="10" VisibleName="Tunnel Settings" url="/vpn_ipsec.php">
|
||||
<Phase1 url="/vpn_ipsec_phase1.php*" visibility="hidden"/>
|
||||
<Phase2 url="/vpn_ipsec_phase2.php*" visibility="hidden"/>
|
||||
</Tunnels>
|
||||
<Mobile order="20" VisibleName="Mobile Clients" url="/vpn_ipsec_mobile.php">
|
||||
<Act url="/vpn_ipsec_mobile.php*" visibility="hidden"/>
|
||||
</Mobile>
|
||||
<Keys order="30" VisibleName="Pre-Shared Keys" url="/vpn_ipsec_keys.php">
|
||||
<Edit url="/vpn_ipsec_keys_edit.php*" visibility="hidden"/>
|
||||
</Keys>
|
||||
<KeyPairs order="40" VisibleName="RSA Key Pairs" url="/ui/ipsec/key-pairs" />
|
||||
<Settings order="50" VisibleName="Advanced Settings" url="/vpn_ipsec_settings.php"/>
|
||||
<Status order="60" VisibleName="Status Overview" url="/diag_ipsec.php">
|
||||
<Act url="/diag_ipsec.php?*" visibility="hidden"/>
|
||||
</Status>
|
||||
<Leases order="70" VisibleName="Lease Status" url="/diag_ipsec_leases.php"/>
|
||||
<SAD order="80" VisibleName="Security Association Database" url="/diag_ipsec_sad.php"/>
|
||||
<SPD order="90" VisibleName="Security Policy Database" url="/diag_ipsec_spd.php"/>
|
||||
<LogFile order="100" VisibleName="Log File" url="/diag_logs_ipsec.php"/>
|
||||
</IPsec>
|
||||
</VPN>
|
||||
</menu>
|
||||
124
src/opnsense/mvc/app/views/OPNsense/IPsec/key_pairs.volt
Normal file
124
src/opnsense/mvc/app/views/OPNsense/IPsec/key_pairs.volt
Normal file
@ -0,0 +1,124 @@
|
||||
{#
|
||||
Copyright (C) 2019 Pascal Mathis <mail@pascalmathis.com>
|
||||
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.
|
||||
#}
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
const $applyLegacyConfig = $('#applyLegacyConfig');
|
||||
const $applyLegacyConfigProgress = $('#applyLegacyConfigProgress');
|
||||
const $responseMsg = $('#responseMsg');
|
||||
const $dirtySubsystemMsg = $('#dirtySubsystemMsg');
|
||||
|
||||
// Helper method to fetch the current status of the legacy subsystem for viewing/hiding the "pending changes" alert
|
||||
function updateLegacyStatus() {
|
||||
ajaxCall('/api/ipsec/legacy-subsystem/status', {}, function (data, status) {
|
||||
if (data['isDirty']) {
|
||||
$responseMsg.addClass('hidden');
|
||||
$dirtySubsystemMsg.removeClass('hidden');
|
||||
} else {
|
||||
$dirtySubsystemMsg.addClass('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Apply config in legacy subsystem
|
||||
$applyLegacyConfig.on('click', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
$applyLegacyConfig.prop('disabled', true);
|
||||
$applyLegacyConfigProgress.addClass('fa fa-spinner fa-pulse');
|
||||
|
||||
ajaxCall('/api/ipsec/legacy-subsystem/applyConfig', {}, function (data, status) {
|
||||
// Preliminarily hide the "pending changes" alert and display the response message if available
|
||||
if (data['message']) {
|
||||
$dirtySubsystemMsg.addClass('hidden');
|
||||
$responseMsg.removeClass('hidden').text(data['message']);
|
||||
}
|
||||
|
||||
// Reset the state of the "apply changes" button
|
||||
$applyLegacyConfig.prop('disabled', false);
|
||||
$applyLegacyConfigProgress.removeClass('fa fa-spinner fa-pulse');
|
||||
|
||||
// Fetch the current legacy subsystem status to ensure changes have been processed
|
||||
updateLegacyStatus();
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize grid for displaying and manipulating key pairs
|
||||
const $grid = $('#grid-key-pairs').UIBootgrid({
|
||||
search: '/api/ipsec/key-pairs/searchItem',
|
||||
get: '/api/ipsec/key-pairs/getItem/',
|
||||
set: '/api/ipsec/key-pairs/setItem/',
|
||||
add: '/api/ipsec/key-pairs/addItem/',
|
||||
del: '/api/ipsec/key-pairs/delItem/',
|
||||
});
|
||||
|
||||
// Refresh status of legacy subsystem when grid has changed
|
||||
$grid.on('loaded.rs.jquery.bootgrid', updateLegacyStatus);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="alert alert-info alert-dismissible hidden" role="alert" id="responseMsg"></div>
|
||||
<div class="alert alert-info hidden" role="alert" id="dirtySubsystemMsg">
|
||||
<button class="btn btn-primary pull-right" type="button" id="applyLegacyConfig">
|
||||
<i id="applyLegacyConfigProgress" class=""></i>
|
||||
{{ lang._('Apply changes') }}
|
||||
</button>
|
||||
<div>
|
||||
{{ lang._('The IPsec tunnel configuration has been changed.') }}<br/>
|
||||
{{ lang._('You must apply the changes in order for them to take effect.') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-box">
|
||||
<table id="grid-key-pairs" class="table table-condensed table-hover table-striped" data-editDialog="DialogKeyPair">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
|
||||
<th data-column-id="name" data-type="string">{{ lang._('Name') }}</th>
|
||||
<th data-column-id="keyType" data-width="20em" data-type="string">{{ lang._('Key Type') }}</th>
|
||||
<th data-column-id="keySize" data-width="20em" data-type="number">{{ lang._('Key Size') }}</th>
|
||||
<th data-column-id="keyFingerprint" data-type="string">{{ lang._('Key Fingerprint') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands"
|
||||
data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default">
|
||||
<span class="fa fa-plus"></span>
|
||||
</button>
|
||||
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default">
|
||||
<span class="fa fa-trash-o"></span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogKeyPair,'id':'DialogKeyPair','label':lang._('Edit key pair')]) }}
|
||||
@ -39,3 +39,9 @@ command:/usr/local/sbin/ipsec restart
|
||||
parameters:
|
||||
type=script
|
||||
message:IPsec service restart
|
||||
|
||||
[reconfigure]
|
||||
command:/usr/local/sbin/pluginctl -c ipsec
|
||||
parameters:
|
||||
type:script
|
||||
message:IPsec config generation
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Pascal Mathis <mail@pascalmathis.com>
|
||||
* Copyright (C) 2014-2015 Deciso B.V.
|
||||
* Copyright (C) 2008 Shrew Soft Inc. <mgrooms@shrew.net>
|
||||
* Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>
|
||||
@ -62,6 +63,14 @@ function ipsec_ikeid_next() {
|
||||
return $ikeid;
|
||||
}
|
||||
|
||||
function ipsec_keypairs()
|
||||
{
|
||||
$mdl = new \OPNsense\IPsec\IPsec();
|
||||
$node = $mdl->getNodeByReference('keyPairs.keyPair');
|
||||
|
||||
return $node ? $node->getNodes() : [];
|
||||
}
|
||||
|
||||
config_read_array('ipsec', 'phase1');
|
||||
config_read_array('ipsec', 'phase2');
|
||||
|
||||
@ -80,7 +89,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
$phase1_fields = "mode,protocol,myid_type,myid_data,peerid_type,peerid_data
|
||||
,encryption-algorithm,lifetime,authentication_method,descr,nat_traversal,rightallowany
|
||||
,interface,iketype,dpd_delay,dpd_maxfail,remote-gateway,pre-shared-key,certref
|
||||
,caref,reauth_enable,rekey_enable,auto,tunnel_isolation,authservers,mobike";
|
||||
,caref,local-kpref,peer-kpref,reauth_enable,rekey_enable,auto,tunnel_isolation,authservers,mobike";
|
||||
if (isset($p1index) && isset($config['ipsec']['phase1'][$p1index])) {
|
||||
// 1-on-1 copy
|
||||
foreach (explode(",", $phase1_fields) as $fieldname) {
|
||||
@ -211,6 +220,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
$reqdfields = explode(" ", "caref certref");
|
||||
$reqdfieldsn = array(gettext("Certificate Authority"),gettext("Certificate"));
|
||||
break;
|
||||
case "pubkey":
|
||||
$reqdfields = explode(" ", "local-kpref peer-kpref");
|
||||
$reqdfieldsn = array(gettext("Local Key Pair"),gettext("Peer Key Pair"));
|
||||
break;
|
||||
}
|
||||
|
||||
if (empty($pconfig['mobile'])) {
|
||||
@ -350,7 +363,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
if (count($input_errors) == 0) {
|
||||
$copy_fields = "ikeid,iketype,interface,mode,protocol,myid_type,myid_data
|
||||
,peerid_type,peerid_data,encryption-algorithm,
|
||||
,lifetime,pre-shared-key,certref,caref,authentication_method,descr
|
||||
,lifetime,pre-shared-key,certref,caref,authentication_method,descr,local-kpref,peer-kpref
|
||||
,nat_traversal,auto,mobike";
|
||||
|
||||
foreach (explode(",",$copy_fields) as $fieldname) {
|
||||
@ -512,6 +525,10 @@ include("head.inc");
|
||||
$(".auth_eap_tls").show();
|
||||
$(".auth_eap_tls :input").prop( "disabled", false );
|
||||
break;
|
||||
case "pubkey":
|
||||
$(".auth_pubkey").show();
|
||||
$(".auth_pubkey :input").prop("disabled", false);
|
||||
break;
|
||||
default: /* psk modes*/
|
||||
$(".auth_psk").show();
|
||||
$(".auth_psk :input").prop( "disabled", false );
|
||||
@ -792,7 +809,7 @@ endforeach; ?>
|
||||
</tr>
|
||||
<?php
|
||||
if (empty($pconfig['mobile'])):?>
|
||||
<tr class="auth_opt auth_eap_tls auth_psk">
|
||||
<tr class="auth_opt auth_eap_tls auth_psk auth_pubkey">
|
||||
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Peer identifier"); ?></td>
|
||||
<td>
|
||||
<select name="peerid_type" id="peerid_type">
|
||||
@ -878,6 +895,52 @@ endforeach; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="auth_opt auth_pubkey">
|
||||
<td><a id="help_for_pubkey_local" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Local Key Pair"); ?></td>
|
||||
<td>
|
||||
<select name="local-kpref">
|
||||
<?php
|
||||
foreach (ipsec_keypairs() as $keypair_uuid => $keypair) :
|
||||
if ($keypair['publicKey'] and $keypair['privateKey']) :
|
||||
?>
|
||||
<option value="<?= $keypair_uuid; ?>" <?= isset($pconfig['local-kpref']) && $pconfig['local-kpref'] == $keypair_uuid ? "selected=\"selected\"" : "" ?>>
|
||||
<?= $keypair['name']; ?>
|
||||
</option>
|
||||
<?php
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
</select>
|
||||
<div class="hidden" data-for="help_for_pubkey_local">
|
||||
<?= gettext("Select a local key pair previously configured at IPsec \\ Key Pairs."); ?>
|
||||
<br />
|
||||
<?= gettext("This selection will only display key pairs which have both a public and private key."); ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="auth_opt auth_pubkey">
|
||||
<td><a id="help_for_pubkey_peer" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Peer Key Pair"); ?></td>
|
||||
<td>
|
||||
<select name="peer-kpref">
|
||||
<?php
|
||||
foreach (ipsec_keypairs() as $keypair_uuid => $keypair) :
|
||||
if ($keypair['publicKey']) :
|
||||
?>
|
||||
<option value="<?= $keypair_uuid; ?>" <?= isset($pconfig['peer-kpref']) && $pconfig['peer-kpref'] == $keypair_uuid ? "selected=\"selected\"" : "" ?>>
|
||||
<?= $keypair['name']; ?>
|
||||
</option>
|
||||
<?php
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
</select>
|
||||
<div class="hidden" data-for="help_for_pubkey_peer">
|
||||
<?=gettext("Select a peer key pair previously configured at IPsec \\ Key Pairs."); ?>
|
||||
<br />
|
||||
<?= gettext("This selection will only display key pairs which have a public key."); ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="auth_opt auth_eap_radius">
|
||||
<td><a id="help_for_authservers" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Radius servers"); ?></td>
|
||||
<td>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user