summaryrefslogtreecommitdiffstats
path: root/src/usr/local/www/system_certmanager.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/local/www/system_certmanager.php')
-rw-r--r--src/usr/local/www/system_certmanager.php156
1 files changed, 150 insertions, 6 deletions
diff --git a/src/usr/local/www/system_certmanager.php b/src/usr/local/www/system_certmanager.php
index 777d416..7b5ea66 100644
--- a/src/usr/local/www/system_certmanager.php
+++ b/src/usr/local/www/system_certmanager.php
@@ -34,6 +34,7 @@ $cert_methods = array(
"import" => gettext("Import an existing Certificate"),
"internal" => gettext("Create an internal Certificate"),
"external" => gettext("Create a Certificate Signing Request"),
+ "sign" => gettext("Sign a Certificate Signing Request")
);
$cert_keylens = array("512", "1024", "2048", "3072", "4096", "7680", "8192", "15360", "16384");
@@ -81,7 +82,6 @@ foreach ($a_ca as $ca) {
$act = $_REQUEST['act'];
-
if ($_POST['act'] == "del") {
if (!isset($a_cert[$id])) {
@@ -96,7 +96,6 @@ if ($_POST['act'] == "del") {
exit;
}
-
if ($act == "new") {
$pconfig['method'] = $_POST['method'];
$pconfig['keylen'] = "2048";
@@ -172,6 +171,7 @@ if ($act == "p12") {
$args['friendly_name'] = $a_cert[$id]['descr'];
$ca = lookup_ca($a_cert[$id]['caref']);
+
if ($ca) {
$args['extracerts'] = openssl_x509_read(base64_decode($ca['crt']));
}
@@ -212,6 +212,24 @@ if ($_POST['save']) {
$pconfig = $_POST;
/* input validation */
+ if ($pconfig['method'] == "sign") {
+ $reqdfields = explode(" ",
+ "descr catosignwith");
+ $reqdfieldsn = array(
+ gettext("Descriptive name"),
+ gettext("CA to sign with"));
+
+ if (($_POST['csrtosign'] === "new") && (!strstr($_POST['csrpaste'], "BEGIN CERTIFICATE REQUEST") || !strstr($_POST['csrpaste'], "END CERTIFICATE REQUEST"))) {
+ $input_errors[] = gettext("This signing request does not appear to be valid.");
+ }
+
+ if ( (($_POST['csrtosign'] === "new") && (strlen($_POST['keypaste']) > 0)) && (!strstr($_POST['keypaste'], "BEGIN PRIVATE KEY") || !strstr($_POST['keypaste'], "END PRIVATE KEY"))) {
+ $input_errors[] = gettext("This private does not appear to be valid.");
+ $input_errors[] = gettext("Key data field should be blank, or a valid x509 private key");
+ }
+
+ }
+
if ($pconfig['method'] == "import") {
$reqdfields = explode(" ",
"descr cert key");
@@ -222,6 +240,7 @@ if ($_POST['save']) {
if ($_POST['cert'] && (!strstr($_POST['cert'], "BEGIN CERTIFICATE") || !strstr($_POST['cert'], "END CERTIFICATE"))) {
$input_errors[] = gettext("This certificate does not appear to be valid.");
}
+
if (cert_get_modulus($_POST['cert'], false) != prv_get_modulus($_POST['key'], false)) {
$input_errors[] = gettext("The submitted private key does not match the submitted certificate data.");
}
@@ -267,6 +286,7 @@ if ($_POST['save']) {
$altnames = array();
do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
+
if ($pconfig['method'] != "import" && $pconfig['method'] != "existing") {
/* subjectAltNames */
foreach ($_POST as $key => $value) {
@@ -362,6 +382,48 @@ if ($_POST['save']) {
if ($cert && $a_user) {
$a_user[$userid]['cert'][] = $cert['refid'];
}
+ } else if ($pconfig['method'] == "sign") { // Sign a CSR
+ $csrid = lookup_cert($pconfig['csrtosign']);
+ $caid = lookup_ca($pconfig['catosignwith']);
+
+ // Read the CSR from $config, or if a new one, from the textarea
+ if ($pconfig['csrtosign'] === "new") {
+ $csr = $pconfig['csrpaste'];
+ } else {
+ $csr = base64_decode($csrid['csr']);
+ }
+
+ $old_err_level = error_reporting(0);
+
+ // Gather the information required for signed cert
+ $ca = base64_decode($caid['crt']);
+ $key = base64_decode($caid['prv']);
+ $duration = $pconfig['duration'];
+ $caref = $pconfig['catosignwith'];
+ $type = (cert_get_purpose($csrid)['server'] === "Yes") ? "server":"user";
+
+ // Sign the new cert and export it in x509 format
+ openssl_x509_export(openssl_csr_sign($csr, $ca, $key, $duration, ['x509_extensions' => 'v3_req']), $n509);
+
+ // Gather the details required to save the new cert
+ $newcert = array();
+ $newcert['refid'] = uniqid();
+ $newcert['caref'] = $caref;
+ $newcert['descr'] = $pconfig['descr'];
+ $newcert['type'] = $type;
+ $newcert['crt'] = base64_encode($n509);
+
+ if ($pconfig['csrtosign'] === "new") {
+ $newcert['prv'] = base64_encode($pconfig['keypaste']);
+ } else {
+ $newcert['prv'] = $csrid['prv'];
+ }
+
+ // Add it to the config file
+ $config['cert'][] = $newcert;
+
+ error_reporting($old_err_level);
+
} else {
$cert = array();
$cert['refid'] = uniqid();
@@ -435,6 +497,7 @@ if ($_POST['save']) {
}
}
}
+
error_reporting($old_err_level);
if (isset($id) && $a_cert[$id]) {
@@ -569,7 +632,7 @@ if ($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)) {
));
}
- $section = new Form_Section('Add a New Certificate');
+ $section = new Form_Section('Add/Sign a New Certificate');
if (!isset($id)) {
$section->addInput(new Form_Select(
@@ -588,6 +651,73 @@ if ($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)) {
))->addClass('toggle-existing');
$form->add($section);
+
+ // Return an array containing the IDs od all CAs
+ function list_cas() {
+ global $a_ca;
+ $allCas = array();
+
+ foreach ($a_ca as $ca) {
+ if ($ca['prv']) {
+ $allCas[$ca['refid']] = $ca['descr'];
+ }
+ }
+
+ return $allCas;
+ }
+
+ // Return an array containing the IDs od all CSRs
+ function list_csrs() {
+ global $config;
+ $allCsrs = array();
+
+ foreach ($config['cert'] as $cert) {
+ if ($cert['csr']) {
+ $allCsrs[$cert['refid']] = $cert['descr'];
+ }
+ }
+
+ return ['new' => gettext('New CSR (Paste below)')] + $allCsrs;
+ }
+
+ $section = new Form_Section('Sign CSR');
+ $section->addClass('toggle-sign collapse');
+
+ $section->AddInput(new Form_Select(
+ 'catosignwith',
+ '*CA to sign with',
+ $pconfig['catosignwith'],
+ list_cas()
+ ));
+
+ $section->AddInput(new Form_Select(
+ 'csrtosign',
+ '*CSR to sign',
+ isset($pconfig['csrtosign']) ? $pconfig['csrtosign'] : 'new',
+ list_csrs()
+ ));
+
+ $section->addInput(new Form_Input(
+ 'duration',
+ '*Certificate duration (days)',
+ 'number',
+ $pconfig['duration'] ? $pconfig['duration']:'3650'
+ ));
+
+ $section->addInput(new Form_Textarea(
+ 'csrpaste',
+ 'CSR data',
+ $pconfig['csrpaste']
+ ))->setHelp('Paste a Certificate Signing Request in X.509 PEM format here.');
+
+ $section->addInput(new Form_Textarea(
+ 'keypaste',
+ 'Key data',
+ $pconfig['keypaste']
+ ))->setHelp('Optionally paste a private key here. The key will be associated with the newly signed certificate in pfSense');
+
+ $form->add($section);
+
$section = new Form_Section('Import Certificate');
$section->addClass('toggle-import collapse');
@@ -1062,7 +1192,9 @@ foreach ($a_cert as $i => $cert):
<td>
<?php if (!$cert['csr']): ?>
<a href="system_certmanager.php?act=exp&amp;id=<?=$i?>" class="fa fa-certificate" title="<?=gettext("Export Certificate")?>"></a>
- <a href="system_certmanager.php?act=key&amp;id=<?=$i?>" class="fa fa-key" title="<?=gettext("Export Key")?>"></a>
+ <?php if ($cert['prv']): ?>
+ <a href="system_certmanager.php?act=key&amp;id=<?=$i?>" class="fa fa-key" title="<?=gettext("Export Key")?>"></a>
+ <?php endif?>
<a href="system_certmanager.php?act=p12&amp;id=<?=$i?>" class="fa fa-archive" title="<?=gettext("Export P12")?>"></a>
<?php else: ?>
<a href="system_certmanager.php?act=csr&amp;id=<?=$i?>" class="fa fa-pencil" title="<?=gettext("Update CSR")?>"></a>
@@ -1086,7 +1218,7 @@ foreach ($a_cert as $i => $cert):
<nav class="action-buttons">
<a href="?act=new" class="btn btn-success btn-sm">
<i class="fa fa-plus icon-embed-btn"></i>
- <?=gettext("Add")?>
+ <?=gettext("Add/Sign")?>
</a>
</nav>
<?php
@@ -1113,7 +1245,6 @@ events.push(function() {
}
$subject = cert_get_subject_array($ca['crt']);
-
?>
case "<?=$ca['refid'];?>":
$('#dn_country').val("<?=$subject[0]['v'];?>");
@@ -1129,15 +1260,28 @@ events.push(function() {
}
}
+ function set_csr_ro() {
+ var newcsr = ($('#csrtosign').val() == "new");
+
+ $('#csrpaste').attr('readonly', !newcsr);
+ $('#keypaste').attr('readonly', !newcsr);
+ setRequired('csrpaste', newcsr);
+ }
+
// ---------- Click checkbox handlers ---------------------------------------------------------
$('#caref').on('change', function() {
internalca_change();
});
+ $('#csrtosign').change(function () {
+ set_csr_ro();
+ });
+
// ---------- On initial page load ------------------------------------------------------------
internalca_change();
+ set_csr_ro();
// Suppress "Delete row" button if there are fewer than two rows
checkLastRow();
OpenPOWER on IntegriCloud