* Add input checks

* Add connections without certificate
* Fix bug with credentials update
This commit is contained in:
Julien VAUBOURG 2014-11-14 00:12:43 +01:00
parent 965bcb8ec6
commit aac96974c6
13 changed files with 296 additions and 57 deletions

6
TODO
View File

@ -1,5 +1,3 @@
* Check input parameters
** in bash install script (empty parameters, are certificates exist, are certificate contain BEGIN CERTIFICATE/PRIVATE)
** in PHP controller (empty parameters, parameters format, compressed IPv6, are certificate contain BEGIN CERTIFICATE/PRIVATE)
* Translate PHP interface in French
* Support VPN without certificates (only login)
* Support VPN without certificates (only login) -- added need just tests
** Add require for slapd for the service start -- added need just tests

View File

@ -1,7 +1,7 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: ynh-vpnclient
# Required-Start: $network $remote_fs $syslog
# Required-Start: $network $remote_fs $syslog slapd
# Required-Stop: $network $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
@ -80,6 +80,12 @@ start_openvpn() {
sed "s|<TPL:SERVER_PORT>|${ynh_server_port}|g" -i /etc/openvpn/client.conf
sed "s|<TPL:PROTO>|${proto}|g" -i /etc/openvpn/client.conf
if [ -e /etc/openvpn/keys/user.key ]; then
sed 's|^<TPL:CERT_COMMENT>||' -i /etc/openvpn/client.conf
else
sed 's|^<TPL:CERT_COMMENT>|;|' -i /etc/openvpn/client.conf
fi
if [[ "${proto}" =~ udp ]]; then
sed 's|^<TPL:UDP_COMMENT>||' -i /etc/openvpn/client.conf
else
@ -140,6 +146,21 @@ moulinette_set() {
fi
}
# Check configuration consistency
if [[ ! "${1}" =~ stop ]]; then
if [ ! -e /etc/openvpn/keys/ca-server.crt ]; then
echo "DISABLED SERVICE: You need a CA server (you can add it through the web admin)" >&2
exit 1
fi
find /etc/openvpn/keys/ -empty -name credentials &> /dev/null
if [ $? -eq 0 -a ! -e /etc/openvpn/keys/user.key ]; then
echo "DISABLED SERVICE: You need either a client certificate, either a username, or both (you can add one through the web admin)" >&2
exit 1
fi
fi
# Variables
echo -n "Retrieving Yunohost settings... "
@ -217,6 +238,9 @@ case "${1}" in
moulinette_set ip6_gw "${new_ip6_gw}"
moulinette_set wired_device "${new_wired_device}"
;;
litestop)
litestop=1
;&
stop)
echo "Stopping..."
@ -234,6 +258,13 @@ case "${1}" in
echo "Stop openvpn"
stop_openvpn
fi
if [ -z "${litestop}" ]; then
yunohost app list -f hotspot --json | grep -q '"installed": true'
if [ $? -eq 0 ]; then
service ynh-hotspot start
fi
fi
;;
status)
exitcode=0
@ -272,7 +303,7 @@ case "${1}" in
exit ${exitcode}
;;
*)
echo "Usage: $0 {start|stop|status}"
echo "Usage: $0 {start|stop|litestop|status}"
exit 1
;;
esac

3
conf/ipv6_compressed Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
sipcalc "${1}" | grep Compressed | awk '{ print $NF; }'

3
conf/ipv6_expanded Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
sipcalc "${1}" | grep Expanded | awk '{ print $NF; }'

View File

@ -20,8 +20,8 @@ port <TPL:SERVER_PORT>
# TLS
tls-client
remote-cert-tls server
cert /etc/openvpn/keys/user.crt
key /etc/openvpn/keys/user.key
<TPL:CERT_COMMENT>cert /etc/openvpn/keys/user.crt
<TPL:CERT_COMMENT>key /etc/openvpn/keys/user.key
ca /etc/openvpn/keys/ca-server.crt
# Logs

View File

@ -43,29 +43,26 @@
{
"name": "crt_client",
"ask": {
"en": "Select the local path of your client certificate (will be moved)",
"fr": "Sélectionnez le chemin local de votre certificat client (le fichier sera déplacé)"
"en": "Select the local path of your client certificate (will be moved ; leave empty if not necessary or if you want to upload it later through the web admin)",
"fr": "Sélectionnez le chemin local de votre certificat client (le fichier sera déplacé ; laisser vide si non-nécessaire ou que vous souhaitez le téléverser plus tard via l'admin web)"
},
"example": "/tmp/user.crt",
"default": "/tmp/user.crt"
"example": "/tmp/user.crt"
},
{
"name": "crt_client_key",
"ask": {
"en": "Select the local path of your client certificate key (will be moved)",
"fr": "Sélectionnez le chemin local de la clé de votre certificat client (le fichier sera déplacé)"
"en": "Select the local path of your client certificate key (will be moved ; leave empty if not necessary or if you want to upload it later through the web admin)",
"fr": "Sélectionnez le chemin local de la clé de votre certificat client (le fichier sera déplacé ; laisser vide si non-nécessaire ou que vous souhaitez le téléverser plus tard via l'admin web)"
},
"example": "/tmp/user.key",
"default": "/tmp/user.key"
"example": "/tmp/user.key"
},
{
"name": "crt_server_ca",
"ask": {
"en": "Select the local path of the server CA (will be moved)",
"fr": "Sélectionnez le chemin local du CA du serveur (le fichier sera déplacé)"
"en": "Select the local path of the server CA (will be moved ; leave empty for uploading it later through the web admin)",
"fr": "Sélectionnez le chemin local du CA du serveur (le fichier sera déplacé ; laisser vide pour le téléverser plus tard via l'admin web)"
},
"example": "/tmp/ca-server.crt",
"default": "/tmp/ca-server.crt"
"example": "/tmp/ca-server.crt"
},
{
"name": "credentials_user",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

@ -11,7 +11,44 @@ login_user=${7}
login_passphrase=${8}
# Check arguments
# TODO
if [ -z "${server_name}" ]; then
echo "ERROR: You need a VPN server name" >&2
exit 1
fi
if [ \( -z "${crt_client_path}" -a ! -z "${crt_client_key_path}" \)\
-o \( ! -z "${crt_client_path}" -a -z "${crt_client_key_path}" \) ]; then
echo "ERROR: A client certificate is needed when you suggest a key (or vice versa)" >&2
exit 1
fi
if [ ! -z "${crt_client_key_path}" -a -z "${crt_server_ca_path}" ]; then
echo "ERROR: If you can suggest a local path for the client certificates, you probably can suggest one other for the (mandatory) CA server" >&2
exit 1
fi
if [ \( -z "${login_user}" -a ! -z "${login_passphrase}" \)\
-o \( ! -z "${login_user}" -a -z "${login_passphrase}" \) ]; then
echo "ERROR: A login password is needed when you suggest a login user (or vice versa)" >&2
exit 1
fi
if [ ! -z "${crt_client_path}" -a ! -f "${crt_client_path}" ]; then
echo "ERROR: The local path <${crt_client_path}> does not exist" >&2
exit 1
fi
if [ ! -z "${crt_client_key_path}" -a ! -f "${crt_client_key_path}" ]; then
echo "ERROR: The local path <${crt_client_key_path}> does not exist" >&2
exit 1
fi
if [ ! -z "${crt_server_ca_path}" -a ! -f "${crt_server_ca_path}" ]; then
echo "ERROR: The local path <${crt_server_ca_path}> does not exist" >&2
exit 1
fi
# Check domain/path availability
sudo yunohost app checkurl ${domain}${url_path} -a vpnclient
@ -31,6 +68,10 @@ sudo yunohost app setting vpnclient ip6_net -v none
sudo yunohost app setting vpnclient login_user -v "${login_user}"
sudo yunohost app setting vpnclient login_passphrase -v "${login_passphrase}"
# Install IPv6 scripts
sudo install -b -o root -g root -m 0755 ../conf/ipv6_expanded /usr/local/bin/
sudo install -b -o root -g root -m 0755 ../conf/ipv6_compressed /usr/local/bin/
# Copy confs
sudo install -b -o root -g root -m 0644 ../conf/openvpn_client.conf.tpl /etc/openvpn/client.conf.tpl
sudo install -b -o root -g root -m 0644 ../conf/nginx_vpnadmin.conf "/etc/nginx/conf.d/${domain}.d/vpnadmin.conf"
@ -48,9 +89,14 @@ sudo find /var/www/vpnadmin/ -type d -exec chmod +x {} \;
sudo mkdir -pm 0770 /etc/openvpn/keys/
sudo chown root:admins /etc/openvpn/keys/
sudo install -b -o root -g admins -m 0660 "${crt_client_path}" /etc/openvpn/keys/user.crt
sudo install -b -o root -g admins -m 0660 "${crt_client_key_path}" /etc/openvpn/keys/user.key
sudo install -b -o root -g admins -m 0660 "${crt_server_ca_path}" /etc/openvpn/keys/ca-server.crt
[ ! -z "${crt_client_path}" ] &&\
sudo install -b -o root -g admins -m 0660 "${crt_client_path}" /etc/openvpn/keys/user.crt
[ ! -z "${crt_client_key_path}" ] &&\
sudo install -b -o root -g admins -m 0660 "${crt_client_key_path}" /etc/openvpn/keys/user.key
[ ! -z "${crt_server_ca_path}" ] &&\
sudo install -b -o root -g admins -m 0660 "${crt_server_ca_path}" /etc/openvpn/keys/ca-server.crt
sudo rm -f "${crt_client_path}" "${crt_client_key_path}" "${crt_server_ca_path}"
@ -98,7 +144,10 @@ sudo yunohost service start php5-fpm
sudo yunohost service add ynh-vpnclient
sudo yunohost service enable ynh-vpnclient
sudo service ynh-vpnclient start
if [ ! -z "${crt_server_ca_path}" ]; then
sudo service ynh-vpnclient start
fi
sudo service nginx reload
@ -108,8 +157,18 @@ sudo yunohost app ssowatconf
# Restart hotspot service if installed to change NAT configuration (now on tun0)
# A new start will fix the interface without unsetting all stuff
sudo yunohost app list -f hotspot --json | grep -q '"installed": true'
if [ $? -eq 0 ]; then
if [ $? -eq 0 -a ! -z "${crt_server_ca_path}" ]; then
sudo service ynh-hotspot start
fi
# Check configuration consistency
if [ -z "${crt_server_ca_path}" ]; then
echo "WARNING: VPN Client is not started because you need to define a server CA through the web admin" >&2
fi
if [ -z "${crt_client_key_path}" -a -z "${login_user}" ]; then
echo "WARNING: VPN Client is not started because you need either a client certificate, either a username (or both)" >&2
fi
exit 0

View File

@ -27,13 +27,6 @@ sudo rm -rf /var/www/vpnadmin/
# Remove user
sudo userdel -f vpnadmin
# Restart hotspot service if installed to change NAT configuration
# A new start will fix the interface without unsetting all stuff
sudo yunohost app list -f hotspot --json | grep -q '"installed": true'
if [ "$?" -eq 0 ]; then
sudo service ynh-hotspot start
fi
# Remove packets
# The yunohost policy is currently to not uninstall packets (dependency problems)
## sudo apt-get --assume-yes --force-yes remove openvpn php5-fpm

View File

@ -1,15 +1,15 @@
<?php
function moulinette_get($var) {
return htmlspecialchars(exec("sudo yunohost app setting vpnclient ".escapeshellarg($var)));
return htmlspecialchars(exec('sudo yunohost app setting vpnclient '.escapeshellarg($var)));
}
function moulinette_set($var, $value) {
return exec("sudo yunohost app setting vpnclient ".escapeshellarg($var)." -v ".escapeshellarg($value));
return exec('sudo yunohost app setting vpnclient '.escapeshellarg($var).' -v '.escapeshellarg($value));
}
function stop_service() {
exec('sudo service ynh-vpnclient stop');
exec('sudo service ynh-vpnclient litestop');
}
function start_service() {
@ -18,6 +18,18 @@ function start_service() {
return $retcode;
}
function ipv6_expanded($ip) {
exec('ipv6_expanded '.escapeshellarg($ip), $output);
return $output[0];
}
function ipv6_compressed($ip) {
exec('ipv6_compressed '.escapeshellarg($ip), $output);
return $output[0];
}
dispatch('/', function() {
$ip6_net = moulinette_get('ip6_net');
$ip6_net = ($ip6_net == 'none') ? '' : $ip6_net;
@ -28,12 +40,72 @@ dispatch('/', function() {
set('login_user', moulinette_get('login_user'));
set('login_passphrase', moulinette_get('login_passphrase'));
set('ip6_net', $ip6_net);
set('crt_client_exists', file_exists('/etc/openvpn/keys/user.crt'));
set('crt_client_key_exists', file_exists('/etc/openvpn/keys/user.key'));
set('crt_server_ca_exists', file_exists('/etc/openvpn/keys/ca-server.crt'));
return render('settings.html.php');
});
dispatch_put('/settings', function() {
$crt_client_exists = file_exists('/etc/openvpn/keys/user.crt');
$crt_client_key_exists = file_exists('/etc/openvpn/keys/user.key');
$crt_server_ca_exists = file_exists('/etc/openvpn/keys/ca-server.crt');
$ip6_net = empty($_POST['ip6_net']) ? 'none' : $_POST['ip6_net'];
$ip6_addr = 'none';
if(empty($_POST['server_name']) || empty($_POST['server_port']) || empty($_POST['server_proto'])) {
flash('error', T_('The Server Address, the Server Port and the Protocol cannot be empty.'));
goto redirect;
}
if(!preg_match('/^\d+$/', $_POST['server_port'])) {
flash('error', T_('The Server Port must be only composed of digits.'));
goto redirect;
}
if($_POST['server_proto'] != 'udp' && $_POST['server_proto'] != 'tcp') {
flash('error', T_('The Protocol must be "udp" or "tcp".'));
goto redirect;
}
if(($_FILES['crt_client']['error'] == UPLOAD_ERR_OK && $_FILES['crt_client_key']['error'] != UPLOAD_ERR_OK && (!$crt_client_key_exists || $_POST['crt_client_key_delete'] == 1))
|| ($_FILES['crt_client_key']['error'] == UPLOAD_ERR_OK && $_FILES['crt_client']['error'] != UPLOAD_ERR_OK && (!$crt_client_exists || $_POST['crt_client_delete'] == 1))) {
flash('error', T_('A Client Certificate is needed when you suggest a Key (or vice versa).'));
goto redirect;
}
if(empty($_POST['login_user']) xor empty($_POST['login_passphrase'])) {
flash('error', T_('A Password is needed when you suggest a Username (or vice versa).'));
goto redirect;
}
if($_FILES['crt_server_ca']['error'] != UPLOAD_ERR_OK && !$crt_server_ca_exists) {
flash('error', T_('You need a Server CA.'));
goto redirect;
}
if(($_FILES['crt_client_key']['error'] != UPLOAD_ERR_OK && (!$crt_client_key_exists || $_POST['crt_client_key_delete'] == 1)) && empty($_POST['login_user'])) {
flash('error', T_('You need either a Client Certificate, either a Username (or both).'));
goto redirect;
}
if($ip6_net != 'none') {
$ip6_net = ipv6_expanded($ip6_net);
if(empty($ip6_net)) {
flash('error', T_('The IPv6 Delegated Prefix format looks bad.'));
goto redirect;
}
$ip6_blocs = explode(':', $ip6_net);
$ip6_addr = "${ip6_blocs[0]}:${ip6_blocs[1]}:${ip6_blocs[2]}:${ip6_blocs[3]}:${ip6_blocs[4]}:${ip6_blocs[5]}:${ip6_blocs[6]}:1";
$ip6_net = ipv6_compressed($ip6_net);
$ip6_addr = ipv6_compressed($ip6_addr);
}
stop_service();
@ -43,27 +115,30 @@ dispatch_put('/settings', function() {
moulinette_set('login_user', $_POST['login_user']);
moulinette_set('login_passphrase', $_POST['login_passphrase']);
moulinette_set('ip6_net', $ip6_net);
# TODO: format ip6_net
if($ip6_net == 'none') {
moulinette_set('ip6_addr', 'none');
} else {
$ip6_addr = "${ip6_net}1";
moulinette_set('ip6_addr', $ip6_addr);
}
moulinette_set('ip6_addr', $ip6_addr);
if($_FILES['crt_client']['error'] == UPLOAD_ERR_OK) {
move_uploaded_file($_FILES['crt_client']['tmp_name'], '/etc/openvpn/keys/user.crt');
} elseif($_POST['crt_client_delete'] == 1) {
unlink('/etc/openvpn/keys/user.crt');
}
if($_FILES['crt_client_key']['error'] == UPLOAD_ERR_OK) {
move_uploaded_file($_FILES['crt_client_key']['tmp_name'], '/etc/openvpn/keys/user.key');
} elseif($_POST['crt_client_key_delete'] == 1) {
unlink('/etc/openvpn/keys/user.key');
}
if($_FILES['crt_server_ca']['error'] == UPLOAD_ERR_OK) {
move_uploaded_file($_FILES['crt_server_ca']['tmp_name'], '/etc/openvpn/keys/ca-server.crt');
}
if(!empty($_POST['login_user'])) {
file_put_contents('/etc/openvpn/keys/credentials', "${_POST['login_user']}\n${_POST['login_passphrase']}");
} else {
file_put_contents('/etc/openvpn/keys/credentials', '');
}
$retcode = start_service();
if($retcode == 0) {
@ -72,6 +147,7 @@ dispatch_put('/settings', function() {
flash('error', T_('Configuration updated but service reload failed'));
}
redirect:
redirect_to('/');
});

View File

@ -0,0 +1,25 @@
a.btn-danger span {
color: #eee;
}
a.btn-danger:hover span {
color: #fff;
}
a.not-allowed {
cursor: not-allowed;
}
input.allowed {
cursor: default;
}
a.btn-disabled, a.btn-disabled:hover, a.btn-disabled:active {
background-color: #999;
background-image: none;
border-color: #888;
}
a.btn-disabled:hover span {
color: #eee;
}

View File

@ -3,12 +3,40 @@ $(document).ready(function() {
$('[data-toggle="tooltip"]').tooltip();
$('.fileinput').click(function() {
var realinputid = '#' + $(this).attr('id').replace(/_chooser.*/, '');
$(realinputid).click();
if(!$(this).hasClass('btn-danger')) {
var realinputid = '#' + $(this).attr('id').replace(/_chooser.*/, '');
$(realinputid).click();
}
});
$('.deletefile').click(function() {
var chooserbtnid = '#' + $(this).attr('id').replace(/_deletebtn$/, '_chooserbtn');
var choosertxtid = '#' + $(this).attr('id').replace(/_deletebtn$/, '_choosertxt');
var fileinputid = '#' + $(this).attr('id').replace(/_deletebtn$/, '');
var deleteinputid = '#' + $(this).attr('id').replace(/btn$/, '');
$(deleteinputid).click();
$(chooserbtnid).toggleClass('btn-danger');
$(chooserbtnid).toggleClass('not-allowed');
$(choosertxtid).toggleClass('btn-danger');
$(choosertxtid).val($(choosertxtid).hasClass('btn-danger') ? 'Removal requested' : '');
$(fileinputid).val('');
if($(this).attr('id').search('_key') >= 0) {
if($(choosertxtid).hasClass('btn-danger') != $('#crt_client_choosertxt').hasClass('btn-danger')) {
$('#crt_client_deletebtn').click();
}
} else {
if($(choosertxtid).hasClass('btn-danger') != $('#crt_client_key_choosertxt').hasClass('btn-danger')) {
$('#crt_client_key_deletebtn').click();
}
}
});
$('input[type="file"]').change(function() {
var choosertxtid = '#' + $(this).attr('id') + '_choosertxt';
$(choosertxtid).val($(this).val());
});
});

View File

@ -42,9 +42,9 @@
</div>
</div>
<div class="panel panel-success">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title" data-toggle="tooltip" data-title="<?= T_('Real Internet') ?>"><?= T_("IPv6") ?></h3>
<h3 class="panel-title"><?= T_("IPv6") ?></h3>
</div>
<div style="padding: 14px 14px 0 10px">
@ -57,6 +57,13 @@
</div>
</div>
<?php if(!$crt_client_key_exists && empty($login_user)): ?>
<div class="alert alert-dismissible alert-warning fade in" style="margin: 2px 0px 17px" role="alert">
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
<strong><?= T_('Notice') ?>:</strong> <?= T_("You need to upload a Client Certificate, or define a Username (or both) for starting your VPN Client.") ?>
</div>
<?php endif; ?>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><?= T_("Certificates") ?></h3>
@ -64,29 +71,48 @@
<div style="padding: 14px 14px 0 10px">
<div class="form-group">
<label for="crt_client" class="col-sm-3 control-label"><?= T_('Update Client Cert.') ?></label>
<label for="crt_client" class="col-sm-3 control-label"><?= $crt_client_exists ? T_('Update Client Cert.') : T_('Upload Client Cert.') ?></label>
<div class="input-group col-sm-9" style="padding: 0 15px">
<input id="crt_client" name="crt_client" type="file" style="display: none" />
<?php if($crt_client_exists): ?>
<a class="btn btn-danger input-group-addon deletefile" id="crt_client_deletebtn" data-toggle="tooltip" data-title="<?= T_('Delete this certificate') ?>"><span class="glyphicon glyphicon-remove"></span></a>
<input id="crt_client_delete" name="crt_client_delete" type="checkbox" value="1" style="display: none" />
<?php endif; ?>
<input type="text" class="form-control fileinput" id="crt_client_choosertxt" placeholder="-----BEGIN CERTIFICATE-----" readonly="readonly" />
<a class="btn input-group-addon fileinput" id="crt_client_chooserbtn"><?= T_('Browse') ?></a>
<input id="crt_client" name="crt_client" type="file" style="display: none" />
<a class="btn input-group-addon fileinput" id="crt_client_chooserbtn" data-toggle="tooltip" data-title="<?= T_('Browse') ?>"><span class="glyphicon glyphicon-search"></span></a>
</div>
</div>
<div class="form-group">
<label for="crt_client_key" class="col-sm-3 control-label"><?= T_('Update Client Key') ?></label>
<label for="crt_client_key" class="col-sm-3 control-label"><?= $crt_client_key_exists ? T_('Update Client Key') : T_('Upload Client Key') ?></label>
<div class="input-group col-sm-9" style="padding: 0 15px">
<input id="crt_client_key" name="crt_client_key" type="file" style="display: none" />
<?php if($crt_client_key_exists): ?>
<a class="btn btn-danger input-group-addon deletefile" id="crt_client_key_deletebtn" data-toggle="tooltip" data-title="<?= T_('Delete this certificate') ?>"><span class="glyphicon glyphicon-remove"></span></a>
<input id="crt_client_key_delete" name="crt_client_key_delete" type="checkbox" value="1" style="display: none" />
<?php endif; ?>
<input type="text" class="form-control fileinput" id="crt_client_key_choosertxt" placeholder="-----BEGIN PRIVATE KEY-----" readonly="readonly" />
<a class="btn input-group-addon fileinput" id="crt_client_key_chooserbtn"><?= T_('Browse') ?></a>
<input id="crt_client_key" name="crt_client_key" type="file" style="display: none" />
<a class="btn input-group-addon fileinput" id="crt_client_key_chooserbtn" data-toggle="tooltip" data-title="<?= T_('Browse') ?>"><span class="glyphicon glyphicon-search"></span></a>
</div>
</div>
<div class="form-group">
<label for="crt_server_ca" class="col-sm-3 control-label"><?= T_('Update Server CA') ?></label>
<?php if(!$crt_server_ca_exists): ?>
<div class="alert alert-dismissible alert-warning fade in" style="margin: 2px 16px 17px" role="alert">
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
<strong><?= T_('Notice') ?>:</strong> <?= T_("You need to upload a Server CA for starting your VPN Client.") ?>
</div>
<?php endif; ?>
<label for="crt_server_ca" class="col-sm-3 control-label"><?= $crt_server_ca_exists ? T_('Update Server CA') : T_('Upload Server CA') ?></label>
<div class="input-group col-sm-9" style="padding: 0 15px">
<input id="crt_server_ca" name="crt_server_ca" type="file" style="display: none" />
<?php if($crt_server_ca_exists): ?>
<a class="btn btn-danger not-allowed btn-disabled input-group-addon" id="crt_server_ca_deletebtn" data-toggle="tooltip" data-title="<?= T_('You cannot have no server CA') ?>"><span class="glyphicon glyphicon-remove"></span></a>
<input id="crt_server_ca_delete" name="crt_server_ca_delete" type="checkbox" value="1" style="display: none" />
<?php endif; ?>
<input type="text" class="form-control fileinput" id="crt_server_ca_choosertxt" placeholder="-----BEGIN CERTIFICATE-----" readonly="readonly" />
<a class="btn input-group-addon fileinput" id="crt_server_ca_chooserbtn"><?= T_('Browse') ?></a>
<input id="crt_server_ca" name="crt_server_ca" type="file" style="display: none" />
<a class="btn input-group-addon fileinput" id="crt_server_ca_chooserbtn" data-toggle="tooltip" data-title="<?= T_('Browse') ?>"><span class="glyphicon glyphicon-search"></span></a>
</div>
</div>
</div>