Project

General

Profile

Download (16 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

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

    
266
<script type="text/javascript">
267
//<![CDATA[
268

    
269
function method_change() {
270

    
271
	method = document.iform.method.value;
272

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

    
285
//]]>
286
</script>
287

    
288
<?php
289

    
290
function build_method_list() {
291
	global $_GET, $crl_methods;
292

    
293
	$list = array();
294

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

    
300
		$list[$method] = $desc;
301
	}
302

    
303
	return($list);
304
}
305

    
306
function build_ca_list() {
307
	global $a_ca;
308

    
309
	$list = array();
310

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

    
315
	return($list);
316
}
317

    
318
function build_cacert_list() {
319
	global $ca_certs;
320

    
321
	$list = array();
322

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

    
327
	return($list);
328
}
329

    
330
if ($input_errors) {
331
	print_input_errors($input_errors);
332
}
333

    
334
if ($savemsg) {
335
	print_info_box($savemsg, $class);
336
}
337

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

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

    
348
		$section = new Form_Section('Create new Revocation List');
349

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

    
357
	}
358

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

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

    
373
	$form->add($section);
374

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

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

    
384
	$form->add($section);
385

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

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

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

    
405
	$form->add($section);
406

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

    
416
	print($form);
417

    
418
} elseif ($act == "editimported") {
419

    
420
	$form = new Form();
421

    
422
	$section = new Form_Section('Edit Imported Certificate Revocation List');
423

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

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

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

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

    
451
	$form->add($section);
452

    
453
	print($form);
454

    
455
} elseif ($act == "edit") {
456
	$crl = $thiscrl;
457

    
458
	$form = new Form(false);
459
?>
460

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

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

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

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

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

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

    
545
		$section->add($group);
546

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

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

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

    
568
		$form->add($section);
569
	}
570

    
571
	print($form);
572
} else {
573
?>
574

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

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

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

    
672

    
673
<?php
674
}
675
?>
676

    
677
<script>
678
//<![CDATA[
679
events.push(function() {
680

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

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

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

    
702
<?php include("foot.inc");
703

    
(194-194/225)