Project

General

Profile

Download (16.2 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 (ctype_alnum($_GET['id'])) {
41
	$id = $_GET['id'];
42
}
43
if (isset($_POST['id']) && ctype_alnum($_POST['id'])) {
44
	$id = $_POST['id'];
45
}
46

    
47
if (!is_array($config['ca'])) {
48
	$config['ca'] = array();
49
}
50

    
51
$a_ca =& $config['ca'];
52

    
53
if (!is_array($config['cert'])) {
54
	$config['cert'] = array();
55
}
56

    
57
$a_cert =& $config['cert'];
58

    
59
if (!is_array($config['crl'])) {
60
	$config['crl'] = array();
61
}
62

    
63
$a_crl =& $config['crl'];
64

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

    
71
$act = $_GET['act'];
72
if ($_POST['act']) {
73
	$act = $_POST['act'];
74
}
75

    
76
if (!empty($id)) {
77
	$thiscrl =& lookup_crl($id);
78
}
79

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

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

    
105
if ($act == "new") {
106
	$pconfig['method'] = $_GET['method'];
107
	$pconfig['caref'] = $_GET['caref'];
108
	$pconfig['lifetime'] = "9999";
109
	$pconfig['serial'] = "0";
110
}
111

    
112
if ($act == "exp") {
113
	crl_update($thiscrl);
114
	$exp_name = urlencode("{$thiscrl['descr']}.crl");
115
	$exp_data = base64_decode($thiscrl['text']);
116
	$exp_size = strlen($exp_data);
117

    
118
	header("Content-Type: application/octet-stream");
119
	header("Content-Disposition: attachment; filename={$exp_name}");
120
	header("Content-Length: $exp_size");
121
	echo $exp_data;
122
	exit;
123
}
124

    
125
if ($act == "addcert") {
126
	if ($_POST) {
127
		unset($input_errors);
128
		$pconfig = $_POST;
129

    
130
		if (!$pconfig['crlref'] || !$pconfig['certref']) {
131
			pfSenseHeader("system_crlmanager.php");
132
			exit;
133
		}
134

    
135
		// certref, crlref
136
		$crl =& lookup_crl($pconfig['crlref']);
137
		$cert = lookup_cert($pconfig['certref']);
138

    
139
		if (!$crl['caref'] || !$cert['caref']) {
140
			$input_errors[] = gettext("Both the Certificate and CRL must be specified.");
141
		}
142

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

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

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

    
195
if ($_POST) {
196
	$input_errors = array();
197
	$pconfig = $_POST;
198

    
199
	/* input validation */
200
	if (($pconfig['method'] == "existing") || ($act == "editimported")) {
201
		$reqdfields = explode(" ", "descr crltext");
202
		$reqdfieldsn = array(
203
			gettext("Descriptive name"),
204
			gettext("Certificate Revocation List data"));
205
	}
206
	if ($pconfig['method'] == "internal") {
207
		$reqdfields = explode(" ", "descr caref");
208
		$reqdfieldsn = array(
209
			gettext("Descriptive name"),
210
			gettext("Certificate Authority"));
211
	}
212

    
213
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
214

    
215
	if (preg_match("/[\?\>\<\&\/\\\"\']/", $pconfig['descr'])) {
216
		array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
217
	}
218

    
219
	/* save modifications */
220
	if (!$input_errors) {
221
		$result = false;
222

    
223
		if ($thiscrl) {
224
			$crl =& $thiscrl;
225
		} else {
226
			$crl = array();
227
			$crl['refid'] = uniqid();
228
		}
229

    
230
		$crl['descr'] = $pconfig['descr'];
231
		if ($act != "editimported") {
232
			$crl['caref'] = $pconfig['caref'];
233
			$crl['method'] = $pconfig['method'];
234
		}
235

    
236
		if (($pconfig['method'] == "existing") || ($act == "editimported")) {
237
			$crl['text'] = base64_encode($pconfig['crltext']);
238
		}
239

    
240
		if ($pconfig['method'] == "internal") {
241
			$crl['serial'] = empty($pconfig['serial']) ? 9999 : $pconfig['serial'];
242
			$crl['lifetime'] = empty($pconfig['lifetime']) ? 9999 : $pconfig['lifetime'];
243
			$crl['cert'] = array();
244
		}
245

    
246
		if (!$thiscrl) {
247
			$a_crl[] = $crl;
248
		}
249

    
250
		write_config("Saved CRL {$crl['descr']}");
251
		// refresh IPsec and OpenVPN CRLs
252
		openvpn_refresh_crls();
253
		vpn_ipsec_configure();
254
		pfSenseHeader("system_crlmanager.php");
255
	}
256
}
257

    
258
$pgtitle = array(gettext("System"), gettext("Certificate Manager"), gettext("Certificate Revocation"));
259
$pglinks = array("", "system_camanager.php", "system_crlmanager.php");
260

    
261
if ($act == "new" || $act == gettext("Save") || $input_errors || $act == "edit") {
262
	$pgtitle[] = gettext('Edit');
263
	$pglinks[] = "@self";
264
}
265
include("head.inc");
266
?>
267

    
268
<script type="text/javascript">
269
//<![CDATA[
270

    
271
function method_change() {
272

    
273
	method = document.iform.method.value;
274

    
275
	switch (method) {
276
		case "internal":
277
			document.getElementById("existing").style.display="none";
278
			document.getElementById("internal").style.display="";
279
			break;
280
		case "existing":
281
			document.getElementById("existing").style.display="";
282
			document.getElementById("internal").style.display="none";
283
			break;
284
	}
285
}
286

    
287
//]]>
288
</script>
289

    
290
<?php
291

    
292
function build_method_list() {
293
	global $_GET, $crl_methods;
294

    
295
	$list = array();
296

    
297
	foreach ($crl_methods as $method => $desc) {
298
		if (($_GET['importonly'] == "yes") && ($method != "existing")) {
299
			continue;
300
		}
301

    
302
		$list[$method] = $desc;
303
	}
304

    
305
	return($list);
306
}
307

    
308
function build_ca_list() {
309
	global $a_ca;
310

    
311
	$list = array();
312

    
313
	foreach ($a_ca as $ca) {
314
		$list[$ca['refid']] = $ca['descr'];
315
	}
316

    
317
	return($list);
318
}
319

    
320
function build_cacert_list() {
321
	global $ca_certs;
322

    
323
	$list = array();
324

    
325
	foreach ($ca_certs as $cert) {
326
		$list[$cert['refid']] = $cert['descr'];
327
	}
328

    
329
	return($list);
330
}
331

    
332
if ($input_errors) {
333
	print_input_errors($input_errors);
334
}
335

    
336
if ($savemsg) {
337
	print_info_box($savemsg, $class);
338
}
339

    
340
$tab_array = array();
341
$tab_array[] = array(gettext("CAs"), false, "system_camanager.php");
342
$tab_array[] = array(gettext("Certificates"), false, "system_certmanager.php");
343
$tab_array[] = array(gettext("Certificate Revocation"), true, "system_crlmanager.php");
344
display_top_tabs($tab_array);
345

    
346
if ($act == "new" || $act == gettext("Save") || $input_errors) {
347
	if (!isset($id)) {
348
		$form = new Form();
349

    
350
		$section = new Form_Section('Create new Revocation List');
351

    
352
		$section->addInput(new Form_Select(
353
			'method',
354
			'Method',
355
			$pconfig['method'],
356
			build_method_list()
357
		));
358

    
359
	}
360

    
361
	$section->addInput(new Form_Input(
362
		'descr',
363
		'Descriptive name',
364
		'text',
365
		$pconfig['descr']
366
	));
367

    
368
	$section->addInput(new Form_Select(
369
		'caref',
370
		'Certificate Authority',
371
		$pconfig['caref'],
372
		build_ca_list()
373
	));
374

    
375
	$form->add($section);
376

    
377
	$section = new Form_Section('Existing Certificate Revocation List');
378
	$section->addClass('existing');
379

    
380
	$section->addInput(new Form_Textarea(
381
		'crltext',
382
		'CRL data',
383
		$pconfig['crltext']
384
		))->setHelp('Paste a Certificate Revocation List in X.509 CRL format here.');
385

    
386
	$form->add($section);
387

    
388
	$section = new Form_Section('Internal Certificate Revocation List');
389
	$section->addClass('internal');
390

    
391
	$section->addInput(new Form_Input(
392
		'lifetime',
393
		'Lifetime (Days)',
394
		'number',
395
		$pconfig['lifetime'],
396
		[max => '9999']
397
	));
398

    
399
	$section->addInput(new Form_Input(
400
		'serial',
401
		'Serial',
402
		'number',
403
		$pconfig['serial'],
404
		['min' => '0', 'max' => '9999']
405
	));
406

    
407
	$form->add($section);
408

    
409
	if (isset($id) && $thiscrl) {
410
		$section->addInput(new Form_Input(
411
			'id',
412
			null,
413
			'hidden',
414
			$id
415
		));
416
	}
417

    
418
	print($form);
419

    
420
} elseif ($act == "editimported") {
421

    
422
	$form = new Form();
423

    
424
	$section = new Form_Section('Edit Imported Certificate Revocation List');
425

    
426
	$section->addInput(new Form_Input(
427
		'descr',
428
		'Descriptive name',
429
		'text',
430
		$pconfig['descr']
431
	));
432

    
433
	$section->addInput(new Form_Textarea(
434
		'crltext',
435
		'CRL data',
436
		$pconfig['crltext']
437
	))->setHelp('Paste a Certificate Revocation List in X.509 CRL format here.');
438

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

    
446
	$section->addInput(new Form_Input(
447
		'act',
448
		null,
449
		'hidden',
450
		'editimported'
451
	));
452

    
453
	$form->add($section);
454

    
455
	print($form);
456

    
457
} elseif ($act == "edit") {
458
	$crl = $thiscrl;
459

    
460
	$form = new Form(false);
461
?>
462

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

    
513
	$ca_certs = array();
514
	foreach ($a_cert as $cert) {
515
		if ($cert['caref'] == $crl['caref'] && !is_cert_revoked($cert, $id)) {
516
			$ca_certs[] = $cert;
517
		}
518
	}
519

    
520
	if (count($ca_certs) == 0) {
521
		print_info_box(gettext("No certificates found for this CA."), 'danger');
522
	} else {
523
		$section = new Form_Section('Choose a Certificate to Revoke');
524
		$group = new Form_Group(null);
525

    
526
		$group->add(new Form_Select(
527
			'certref',
528
			null,
529
			$pconfig['certref'],
530
			build_cacert_list()
531
			))->setWidth(4)->setHelp('Certificate');
532

    
533
		$group->add(new Form_Select(
534
			'crlreason',
535
			null,
536
			-1,
537
			$openssl_crl_status
538
			))->setHelp('Reason');
539

    
540
		$group->add(new Form_Button(
541
			'submit',
542
			'Add',
543
			null,
544
			'fa-plus'
545
			))->addClass('btn-success btn-sm');
546

    
547
		$section->add($group);
548

    
549
		$section->addInput(new Form_Input(
550
			'id',
551
			null,
552
			'hidden',
553
			$crl['refid']
554
		));
555

    
556
		$section->addInput(new Form_Input(
557
			'act',
558
			null,
559
			'hidden',
560
			'addcert'
561
		));
562

    
563
		$section->addInput(new Form_Input(
564
			'crlref',
565
			null,
566
			'hidden',
567
			$crl['refid']
568
		));
569

    
570
		$form->add($section);
571
	}
572

    
573
	print($form);
574
} else {
575
?>
576

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

    
598
	$i = 0;
599
	foreach ($a_ca as $ca):
600
		$name = htmlspecialchars($ca['descr']);
601

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

    
674

    
675
<?php
676
}
677
?>
678

    
679
<script type="text/javascript">
680
//<![CDATA[
681
events.push(function() {
682

    
683
	// Hides all elements of the specified class. This will usually be a section or group
684
	function hideClass(s_class, hide) {
685
		if (hide) {
686
			$('.' + s_class).hide();
687
		} else {
688
			$('.' + s_class).show();
689
		}
690
	}
691

    
692
	// When the 'method" selector is changed, we show/hide certain sections
693
	$('#method').on('change', function() {
694
		hideClass('internal', ($('#method').val() == 'existing'));
695
		hideClass('existing', ($('#method').val() == 'internal'));
696
	});
697

    
698
	hideClass('internal', ($('#method').val() == 'existing'));
699
	hideClass('existing', ($('#method').val() == 'internal'));
700
});
701
//]]>
702
</script>
703

    
704
<?php include("foot.inc");
705

    
(194-194/225)