Project

General

Profile

Download (16.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * system_crlmanager.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 * http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21

    
22
##|+PRIV
23
##|*IDENT=page-system-crlmanager
24
##|*NAME=System: CRL Manager
25
##|*DESCR=Allow access to the 'System: CRL Manager' page.
26
##|*MATCH=system_crlmanager.php*
27
##|-PRIV
28

    
29
require_once("guiconfig.inc");
30
require_once("certs.inc");
31
require_once("openvpn.inc");
32
require_once("vpn.inc");
33

    
34
global $openssl_crl_status;
35

    
36
$crl_methods = array(
37
	"internal" => gettext("Create an internal Certificate Revocation List"),
38
	"existing" => gettext("Import an existing Certificate Revocation List"));
39

    
40
if (isset($_REQUEST['id']) && ctype_alnum($_REQUEST['id'])) {
41
	$id = $_REQUEST['id'];
42
}
43

    
44
if (!is_array($config['ca'])) {
45
	$config['ca'] = array();
46
}
47

    
48
$a_ca =& $config['ca'];
49

    
50
if (!is_array($config['cert'])) {
51
	$config['cert'] = array();
52
}
53

    
54
$a_cert =& $config['cert'];
55

    
56
if (!is_array($config['crl'])) {
57
	$config['crl'] = array();
58
}
59

    
60
$a_crl =& $config['crl'];
61

    
62
foreach ($a_crl as $cid => $acrl) {
63
	if (!isset($acrl['refid'])) {
64
		unset ($a_crl[$cid]);
65
	}
66
}
67

    
68
$act = $_REQUEST['act'];
69

    
70

    
71
if (!empty($id)) {
72
	$thiscrl =& lookup_crl($id);
73
}
74

    
75
// If we were given an invalid crlref in the id, no sense in continuing as it would only cause errors.
76
if (!$thiscrl && (($act != "") && ($act != "new"))) {
77
	pfSenseHeader("system_crlmanager.php");
78
	$act="";
79
	$savemsg = gettext("Invalid CRL reference.");
80
	$class = "danger";
81
}
82

    
83
if ($_POST['act'] == "del") {
84
	$name = htmlspecialchars($thiscrl['descr']);
85
	if (crl_in_use($id)) {
86
		$savemsg = sprintf(gettext("Certificate Revocation List %s is in use and cannot be deleted."), $name);
87
		$class = "danger";
88
	} else {
89
		foreach ($a_crl as $cid => $acrl) {
90
			if ($acrl['refid'] == $thiscrl['refid']) {
91
				unset($a_crl[$cid]);
92
			}
93
		}
94
		write_config("Deleted CRL {$name}.");
95
		$savemsg = sprintf(gettext("Certificate Revocation List %s successfully deleted."), $name);
96
		$class = "success";
97
	}
98
}
99

    
100
if ($act == "new") {
101
	$pconfig['method'] = $_REQUEST['method'];
102
	$pconfig['caref'] = $_REQUEST['caref'];
103
	$pconfig['lifetime'] = "9999";
104
	$pconfig['serial'] = "0";
105
}
106

    
107
if ($act == "exp") {
108
	crl_update($thiscrl);
109
	$exp_name = urlencode("{$thiscrl['descr']}.crl");
110
	$exp_data = base64_decode($thiscrl['text']);
111
	$exp_size = strlen($exp_data);
112

    
113
	header("Content-Type: application/octet-stream");
114
	header("Content-Disposition: attachment; filename={$exp_name}");
115
	header("Content-Length: $exp_size");
116
	echo $exp_data;
117
	exit;
118
}
119

    
120
if ($act == "addcert") {
121

    
122
	unset($input_errors);
123
	$pconfig = $_REQUEST;
124

    
125
	if (!$pconfig['crlref'] || !$pconfig['certref']) {
126
		pfSenseHeader("system_crlmanager.php");
127
		exit;
128
	}
129

    
130
	// certref, crlref
131
	$crl =& lookup_crl($pconfig['crlref']);
132
	$cert = lookup_cert($pconfig['certref']);
133

    
134
	if (!$crl['caref'] || !$cert['caref']) {
135
		$input_errors[] = gettext("Both the Certificate and CRL must be specified.");
136
	}
137

    
138
	if ($crl['caref'] != $cert['caref']) {
139
		$input_errors[] = gettext("CA mismatch between the Certificate and CRL. Unable to Revoke.");
140
	}
141
	if (!is_crl_internal($crl)) {
142
		$input_errors[] = gettext("Cannot revoke certificates for an imported/external CRL.");
143
	}
144

    
145
	if (!$input_errors) {
146
		$reason = (empty($pconfig['crlreason'])) ? OCSP_REVOKED_STATUS_UNSPECIFIED : $pconfig['crlreason'];
147
		cert_revoke($cert, $crl, $reason);
148
		// refresh IPsec and OpenVPN CRLs
149
		openvpn_refresh_crls();
150
		vpn_ipsec_configure();
151
		write_config("Revoked cert {$cert['descr']} in CRL {$crl['descr']}.");
152
		pfSenseHeader("system_crlmanager.php");
153
		exit;
154
	}
155
}
156

    
157
if ($act == "delcert") {
158
	if (!is_array($thiscrl['cert'])) {
159
		pfSenseHeader("system_crlmanager.php");
160
		exit;
161
	}
162
	$found = false;
163
	foreach ($thiscrl['cert'] as $acert) {
164
		if ($acert['refid'] == $_REQUEST['certref']) {
165
			$found = true;
166
			$thiscert = $acert;
167
		}
168
	}
169
	if (!$found) {
170
		pfSenseHeader("system_crlmanager.php");
171
		exit;
172
	}
173
	$certname = htmlspecialchars($thiscert['descr']);
174
	$crlname = htmlspecialchars($thiscrl['descr']);
175
	if (cert_unrevoke($thiscert, $thiscrl)) {
176
		$savemsg = sprintf(gettext('Deleted Certificate %1$s from CRL %2$s.'), $certname, $crlname);
177
		$class = "success";
178
		// refresh IPsec and OpenVPN CRLs
179
		openvpn_refresh_crls();
180
		vpn_ipsec_configure();
181
		write_config($savemsg);
182
	} else {
183
		$savemsg = sprintf(gettext('Failed to delete Certificate %1$s from CRL %2$s.'), $certname, $crlname);
184
		$class = "danger";
185
	}
186
	$act="edit";
187
}
188

    
189
if ($_POST['save']) {
190
	$input_errors = array();
191
	$pconfig = $_POST;
192

    
193
	/* input validation */
194
	if (($pconfig['method'] == "existing") || ($act == "editimported")) {
195
		$reqdfields = explode(" ", "descr crltext");
196
		$reqdfieldsn = array(
197
			gettext("Descriptive name"),
198
			gettext("Certificate Revocation List data"));
199
	}
200
	if ($pconfig['method'] == "internal") {
201
		$reqdfields = explode(" ", "descr caref");
202
		$reqdfieldsn = array(
203
			gettext("Descriptive name"),
204
			gettext("Certificate Authority"));
205
	}
206

    
207
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
208

    
209
	if (preg_match("/[\?\>\<\&\/\\\"\']/", $pconfig['descr'])) {
210
		array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
211
	}
212

    
213
	/* save modifications */
214
	if (!$input_errors) {
215
		$result = false;
216

    
217
		if ($thiscrl) {
218
			$crl =& $thiscrl;
219
		} else {
220
			$crl = array();
221
			$crl['refid'] = uniqid();
222
		}
223

    
224
		$crl['descr'] = $pconfig['descr'];
225
		if ($act != "editimported") {
226
			$crl['caref'] = $pconfig['caref'];
227
			$crl['method'] = $pconfig['method'];
228
		}
229

    
230
		if (($pconfig['method'] == "existing") || ($act == "editimported")) {
231
			$crl['text'] = base64_encode($pconfig['crltext']);
232
		}
233

    
234
		if ($pconfig['method'] == "internal") {
235
			$crl['serial'] = empty($pconfig['serial']) ? 9999 : $pconfig['serial'];
236
			$crl['lifetime'] = empty($pconfig['lifetime']) ? 9999 : $pconfig['lifetime'];
237
			$crl['cert'] = array();
238
		}
239

    
240
		if (!$thiscrl) {
241
			$a_crl[] = $crl;
242
		}
243

    
244
		write_config("Saved CRL {$crl['descr']}");
245
		// refresh IPsec and OpenVPN CRLs
246
		openvpn_refresh_crls();
247
		vpn_ipsec_configure();
248
		pfSenseHeader("system_crlmanager.php");
249
	}
250
}
251

    
252
$pgtitle = array(gettext("System"), gettext("Certificate Manager"), gettext("Certificate Revocation"));
253
$pglinks = array("", "system_camanager.php", "system_crlmanager.php");
254

    
255
if ($act == "new" || $act == gettext("Save") || $input_errors || $act == "edit") {
256
	$pgtitle[] = gettext('Edit');
257
	$pglinks[] = "@self";
258
}
259
include("head.inc");
260
?>
261

    
262
<script type="text/javascript">
263
//<![CDATA[
264

    
265
function method_change() {
266

    
267
	method = document.iform.method.value;
268

    
269
	switch (method) {
270
		case "internal":
271
			document.getElementById("existing").style.display="none";
272
			document.getElementById("internal").style.display="";
273
			break;
274
		case "existing":
275
			document.getElementById("existing").style.display="";
276
			document.getElementById("internal").style.display="none";
277
			break;
278
	}
279
}
280

    
281
//]]>
282
</script>
283

    
284
<?php
285

    
286
function build_method_list() {
287
	global $_POST, $crl_methods;
288

    
289
	$list = array();
290

    
291
	foreach ($crl_methods as $method => $desc) {
292
		if (($_POST['importonly'] == "yes") && ($method != "existing")) {
293
			continue;
294
		}
295

    
296
		$list[$method] = $desc;
297
	}
298

    
299
	return($list);
300
}
301

    
302
function build_ca_list() {
303
	global $a_ca;
304

    
305
	$list = array();
306

    
307
	foreach ($a_ca as $ca) {
308
		$list[$ca['refid']] = $ca['descr'];
309
	}
310

    
311
	return($list);
312
}
313

    
314
function build_cacert_list() {
315
	global $ca_certs;
316

    
317
	$list = array();
318

    
319
	foreach ($ca_certs as $cert) {
320
		$list[$cert['refid']] = $cert['descr'];
321
	}
322

    
323
	return($list);
324
}
325

    
326
if ($input_errors) {
327
	print_input_errors($input_errors);
328
}
329

    
330
if ($savemsg) {
331
	print_info_box($savemsg, $class);
332
}
333

    
334
$tab_array = array();
335
$tab_array[] = array(gettext("CAs"), false, "system_camanager.php");
336
$tab_array[] = array(gettext("Certificates"), false, "system_certmanager.php");
337
$tab_array[] = array(gettext("Certificate Revocation"), true, "system_crlmanager.php");
338
display_top_tabs($tab_array);
339

    
340
if ($act == "new" || $act == gettext("Save") || $input_errors) {
341
	if (!isset($id)) {
342
		$form = new Form();
343

    
344
		$section = new Form_Section('Create new Revocation List');
345

    
346
		$section->addInput(new Form_Select(
347
			'method',
348
			'*Method',
349
			$pconfig['method'],
350
			build_method_list()
351
		));
352

    
353
	}
354

    
355
	$section->addInput(new Form_Input(
356
		'descr',
357
		'*Descriptive name',
358
		'text',
359
		$pconfig['descr']
360
	));
361

    
362
	$section->addInput(new Form_Select(
363
		'caref',
364
		'*Certificate Authority',
365
		$pconfig['caref'],
366
		build_ca_list()
367
	));
368

    
369
	$form->add($section);
370

    
371
	$section = new Form_Section('Existing Certificate Revocation List');
372
	$section->addClass('existing');
373

    
374
	$section->addInput(new Form_Textarea(
375
		'crltext',
376
		'*CRL data',
377
		$pconfig['crltext']
378
		))->setHelp('Paste a Certificate Revocation List in X.509 CRL format here.');
379

    
380
	$form->add($section);
381

    
382
	$section = new Form_Section('Internal Certificate Revocation List');
383
	$section->addClass('internal');
384

    
385
	$section->addInput(new Form_Input(
386
		'lifetime',
387
		'Lifetime (Days)',
388
		'number',
389
		$pconfig['lifetime'],
390
		[max => '9999']
391
	));
392

    
393
	$section->addInput(new Form_Input(
394
		'serial',
395
		'Serial',
396
		'number',
397
		$pconfig['serial'],
398
		['min' => '0', 'max' => '9999']
399
	));
400

    
401
	$form->add($section);
402

    
403
	if (isset($id) && $thiscrl) {
404
		$section->addInput(new Form_Input(
405
			'id',
406
			null,
407
			'hidden',
408
			$id
409
		));
410
	}
411

    
412
	print($form);
413

    
414
} elseif ($act == "editimported") {
415

    
416
	$form = new Form();
417

    
418
	$section = new Form_Section('Edit Imported Certificate Revocation List');
419

    
420
	$section->addInput(new Form_Input(
421
		'descr',
422
		'*Descriptive name',
423
		'text',
424
		$pconfig['descr']
425
	));
426

    
427
	$section->addInput(new Form_Textarea(
428
		'crltext',
429
		'*CRL data',
430
		$pconfig['crltext']
431
	))->setHelp('Paste a Certificate Revocation List in X.509 CRL format here.');
432

    
433
	$section->addInput(new Form_Input(
434
		'id',
435
		null,
436
		'hidden',
437
		$id
438
	));
439

    
440
	$section->addInput(new Form_Input(
441
		'act',
442
		null,
443
		'hidden',
444
		'editimported'
445
	));
446

    
447
	$form->add($section);
448

    
449
	print($form);
450

    
451
} elseif ($act == "edit") {
452
	$crl = $thiscrl;
453

    
454
	$form = new Form(false);
455
?>
456

    
457
	<div class="panel panel-default">
458
		<div class="panel-heading"><h2 class="panel-title"><?=gettext("Currently Revoked Certificates for CRL") . ': ' . $crl['descr']?></h2></div>
459
		<div class="panel-body table-responsive">
460
<?php
461
	if (!is_array($crl['cert']) || (count($crl['cert']) == 0)) {
462
		print_info_box(gettext("No certificates found for this CRL."), 'danger');
463
	} else {
464
?>
465
			<table class="table table-striped table-hover table-condensed">
466
				<thead>
467
					<tr>
468
						<th><?=gettext("Certificate Name")?></th>
469
						<th><?=gettext("Revocation Reason")?></th>
470
						<th><?=gettext("Revoked At")?></th>
471
						<th></th>
472
					</tr>
473
				</thead>
474
				<tbody>
475
<?php
476
		foreach ($crl['cert'] as $i => $cert):
477
			$name = htmlspecialchars($cert['descr']);
478
?>
479
					<tr>
480
						<td class="listlr">
481
							<?=$name; ?>
482
						</td>
483
						<td class="listlr">
484
							<?=$openssl_crl_status[$cert["reason"]]; ?>
485
						</td>
486
						<td class="listlr">
487
							<?=date("D M j G:i:s T Y", $cert["revoke_time"]); ?>
488
						</td>
489
						<td class="list">
490
							<a href="system_crlmanager.php?act=delcert&amp;id=<?=$crl['refid']; ?>&amp;certref=<?=$cert['refid']; ?>" usepost>
491
								<i class="fa fa-trash" title="<?=gettext("Delete this certificate from the CRL")?>" alt="<?=gettext("Delete this certificate from the CRL")?>"></i>
492
							</a>
493
						</td>
494
					</tr>
495
<?php
496
		endforeach;
497
?>
498
				</tbody>
499
			</table>
500
<?php
501
	}
502
?>
503
		</div>
504
	</div>
505
<?php
506

    
507
	$ca_certs = array();
508
	foreach ($a_cert as $cert) {
509
		if ($cert['caref'] == $crl['caref'] && !is_cert_revoked($cert, $id)) {
510
			$ca_certs[] = $cert;
511
		}
512
	}
513

    
514
	if (count($ca_certs) == 0) {
515
		print_info_box(gettext("No certificates found for this CA."), 'danger');
516
	} else {
517
		$section = new Form_Section('Choose a Certificate to Revoke');
518
		$group = new Form_Group(null);
519

    
520
		$group->add(new Form_Select(
521
			'certref',
522
			null,
523
			$pconfig['certref'],
524
			build_cacert_list()
525
			))->setWidth(4)->setHelp('Certificate');
526

    
527
		$group->add(new Form_Select(
528
			'crlreason',
529
			null,
530
			-1,
531
			$openssl_crl_status
532
			))->setHelp('Reason');
533

    
534
		$group->add(new Form_Button(
535
			'submit',
536
			'Add',
537
			null,
538
			'fa-plus'
539
			))->addClass('btn-success btn-sm');
540

    
541
		$section->add($group);
542

    
543
		$section->addInput(new Form_Input(
544
			'id',
545
			null,
546
			'hidden',
547
			$crl['refid']
548
		));
549

    
550
		$section->addInput(new Form_Input(
551
			'act',
552
			null,
553
			'hidden',
554
			'addcert'
555
		));
556

    
557
		$section->addInput(new Form_Input(
558
			'crlref',
559
			null,
560
			'hidden',
561
			$crl['refid']
562
		));
563

    
564
		$form->add($section);
565
	}
566

    
567
	print($form);
568
} else {
569
?>
570

    
571
	<div class="panel panel-default">
572
		<div class="panel-heading"><h2 class="panel-title"><?=gettext("Additional Certificate Revocation Lists")?></h2></div>
573
		<div class="panel-body table-responsive">
574
			<table class="table table-striped table-hover table-condensed table-rowdblclickedit">
575
				<thead>
576
					<tr>
577
						<th><?=gettext("Name")?></th>
578
						<th><?=gettext("Internal")?></th>
579
						<th><?=gettext("Certificates")?></th>
580
						<th><?=gettext("In Use")?></th>
581
						<th><?=gettext("Actions")?></th>
582
					</tr>
583
				</thead>
584
				<tbody>
585
<?php
586
	// Map CRLs to CAs in one pass
587
	$ca_crl_map = array();
588
	foreach ($a_crl as $crl) {
589
		$ca_crl_map[$crl['caref']][] = $crl['refid'];
590
	}
591

    
592
	$i = 0;
593
	foreach ($a_ca as $ca):
594
		$name = htmlspecialchars($ca['descr']);
595

    
596
		if ($ca['prv']) {
597
			$cainternal = "YES";
598
		} else {
599
			$cainternal = "NO";
600
		}
601
?>
602
					<tr>
603
						<td colspan="4">
604
							<?=$name?>
605
						</td>
606
						<td>
607
<?php
608
		if ($cainternal == "YES"):
609
?>
610
							<a href="system_crlmanager.php?act=new&amp;caref=<?=$ca['refid']; ?>" class="btn btn-xs btn-success">
611
								<i class="fa fa-plus icon-embed-btn"></i>
612
								<?=gettext("Add or Import CRL")?>
613
							</a>
614
<?php
615
		else:
616
?>
617
							<a href="system_crlmanager.php?act=new&amp;caref=<?=$ca['refid']; ?>&amp;importonly=yes" class="btn btn-xs btn-success">
618
								<i class="fa fa-plus icon-embed-btn"></i>
619
								<?=gettext("Add or Import CRL")?>
620
							</a>
621
<?php
622
		endif;
623
?>
624
						</td>
625
					</tr>
626
<?php
627
		if (is_array($ca_crl_map[$ca['refid']])):
628
			foreach ($ca_crl_map[$ca['refid']] as $crl):
629
				$tmpcrl = lookup_crl($crl);
630
				$internal = is_crl_internal($tmpcrl);
631
				$inuse = crl_in_use($tmpcrl['refid']);
632
?>
633
					<tr>
634
						<td><?=$tmpcrl['descr']; ?></td>
635
						<td><i class="fa fa-<?=($internal) ? "check" : "times"; ?>"></i></td>
636
						<td><?=($internal) ? count($tmpcrl['cert']) : "Unknown (imported)"; ?></td>
637
						<td><i class="fa fa-<?=($inuse) ? "check" : "times"; ?>"></i></td>
638
						<td>
639
							<a href="system_crlmanager.php?act=exp&amp;id=<?=$tmpcrl['refid']?>" class="fa fa-download" title="<?=gettext("Export CRL")?>" ></a>
640
<?php
641
				if ($internal): ?>
642
							<a href="system_crlmanager.php?act=edit&amp;id=<?=$tmpcrl['refid']?>" class="fa fa-pencil" title="<?=gettext("Edit CRL")?>"></a>
643
<?php
644
				else:
645
?>
646
							<a href="system_crlmanager.php?act=editimported&amp;id=<?=$tmpcrl['refid']?>" class="fa fa-pencil" title="<?=gettext("Edit CRL")?>"></a>
647
<?php			endif;
648
				if (!$inuse):
649
?>
650
							<a href="system_crlmanager.php?act=del&amp;id=<?=$tmpcrl['refid']?>" class="fa fa-trash" title="<?=gettext("Delete CRL")?>" usepost></a>
651
<?php
652
				endif;
653
?>
654
						</td>
655
					</tr>
656
<?php
657
				$i++;
658
				endforeach;
659
			endif;
660
			$i++;
661
		endforeach;
662
?>
663
				</tbody>
664
			</table>
665
		</div>
666
	</div>
667

    
668

    
669
<?php
670
}
671
?>
672

    
673
<script type="text/javascript">
674
//<![CDATA[
675
events.push(function() {
676

    
677
	// Hides all elements of the specified class. This will usually be a section or group
678
	function hideClass(s_class, hide) {
679
		if (hide) {
680
			$('.' + s_class).hide();
681
		} else {
682
			$('.' + s_class).show();
683
		}
684
	}
685

    
686
	// When the 'method" selector is changed, we show/hide certain sections
687
	$('#method').on('change', function() {
688
		hideClass('internal', ($('#method').val() == 'existing'));
689
		hideClass('existing', ($('#method').val() == 'internal'));
690
	});
691

    
692
	hideClass('internal', ($('#method').val() == 'existing'));
693
	hideClass('existing', ($('#method').val() == 'internal'));
694
});
695
//]]>
696
</script>
697

    
698
<?php include("foot.inc");
699

    
(192-192/223)