Project

General

Profile

Download (16.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	system_crlmanager.php
4

    
5
	Copyright (C) 2010 Jim Pingle
6
	Copyright (C) 2013-2015 Electric Sheep Fencing, LP
7
	All rights reserved.
8

    
9
	Redistribution and use in source and binary forms, with or without
10
	modification, are permitted provided that the following conditions are met:
11

    
12
	1. Redistributions of source code must retain the above copyright notice,
13
	this list of conditions and the following disclaimer.
14

    
15
	2. Redistributions in binary form must reproduce the above copyright
16
	notice, this list of conditions and the following disclaimer in the
17
	documentation and/or other materials provided with the distribution.
18

    
19
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
	POSSIBILITY OF SUCH DAMAGE.
29
*/
30
/*
31
	pfSense_MODULE:	certificate_manager
32
*/
33

    
34
##|+PRIV
35
##|*IDENT=page-system-crlmanager
36
##|*NAME=System: CRL Manager
37
##|*DESCR=Allow access to the 'System: CRL Manager' page.
38
##|*MATCH=system_crlmanager.php*
39
##|-PRIV
40

    
41
require("guiconfig.inc");
42
require_once("certs.inc");
43
require_once("openvpn.inc");
44
require_once("vpn.inc");
45

    
46
global $openssl_crl_status;
47

    
48
$pgtitle = array(gettext("System"), gettext("Certificate Revocation List Manager"));
49

    
50
$crl_methods = array(
51
	"internal" => gettext("Create an internal Certificate Revocation List"),
52
	"existing" => gettext("Import an existing Certificate Revocation List"));
53

    
54
if (ctype_alnum($_GET['id'])) {
55
	$id = $_GET['id'];
56
}
57
if (isset($_POST['id']) && ctype_alnum($_POST['id'])) {
58
	$id = $_POST['id'];
59
}
60

    
61
if (!is_array($config['ca'])) {
62
	$config['ca'] = array();
63
}
64

    
65
$a_ca =& $config['ca'];
66

    
67
if (!is_array($config['cert'])) {
68
	$config['cert'] = array();
69
}
70

    
71
$a_cert =& $config['cert'];
72

    
73
if (!is_array($config['crl'])) {
74
	$config['crl'] = array();
75
}
76

    
77
$a_crl =& $config['crl'];
78

    
79
foreach ($a_crl as $cid => $acrl) {
80
	if (!isset($acrl['refid'])) {
81
		unset ($a_crl[$cid]);
82
	}
83
}
84

    
85
$act = $_GET['act'];
86
if ($_POST['act']) {
87
	$act = $_POST['act'];
88
}
89

    
90
if (!empty($id)) {
91
	$thiscrl =& lookup_crl($id);
92
}
93

    
94
// If we were given an invalid crlref in the id, no sense in continuing as it would only cause errors.
95
if (!$thiscrl && (($act != "") && ($act != "new"))) {
96
	pfSenseHeader("system_crlmanager.php");
97
	$act="";
98
	$savemsg = gettext("Invalid CRL reference.");
99
}	
100

    
101
if ($act == "del") {
102
	$name = htmlspecialchars($thiscrl['descr']);
103
	if (crl_in_use($id)) {
104
		$savemsg = sprintf(gettext("Certificate Revocation List %s is in use and cannot be deleted"), $name) . "<br />";
105
	} else {
106
		foreach ($a_crl as $cid => $acrl) {
107
			if ($acrl['refid'] == $thiscrl['refid']) {
108
				unset($a_crl[$cid]);
109
			}
110
		}
111
		write_config("Deleted CRL {$name}.");
112
		$savemsg = sprintf(gettext("Certificate Revocation List %s successfully deleted"), $name) . "<br />";
113
	}
114
}
115

    
116
if ($act == "new") {
117
	$pconfig['method'] = $_GET['method'];
118
	$pconfig['caref'] = $_GET['caref'];
119
	$pconfig['lifetime'] = "9999";
120
	$pconfig['serial'] = "0";
121
}
122

    
123
if ($act == "exp") {
124
	crl_update($thiscrl);
125
	$exp_name = urlencode("{$thiscrl['descr']}.crl");
126
	$exp_data = base64_decode($thiscrl['text']);
127
	$exp_size = strlen($exp_data);
128

    
129
	header("Content-Type: application/octet-stream");
130
	header("Content-Disposition: attachment; filename={$exp_name}");
131
	header("Content-Length: $exp_size");
132
	echo $exp_data;
133
	exit;
134
}
135

    
136
if ($act == "addcert") {
137
	if ($_POST) {
138
		unset($input_errors);
139
		$pconfig = $_POST;
140

    
141
		if (!$pconfig['crlref'] || !$pconfig['certref']) {
142
			pfSenseHeader("system_crlmanager.php");
143
			exit;
144
		}
145

    
146
		// certref, crlref
147
		$crl =& lookup_crl($pconfig['crlref']);
148
		$cert = lookup_cert($pconfig['certref']);
149

    
150
		if (!$crl['caref'] || !$cert['caref']) {
151
			$input_errors[] = gettext("Both the Certificate and CRL must be specified.");
152
		}
153

    
154
		if ($crl['caref'] != $cert['caref']) {
155
			$input_errors[] = gettext("CA mismatch between the Certificate and CRL. Unable to Revoke.");
156
		}
157
		if (!is_crl_internal($crl)) {
158
			$input_errors[] = gettext("Cannot revoke certificates for an imported/external CRL.");
159
		}
160

    
161
		if (!$input_errors) {
162
			$reason = (empty($pconfig['crlreason'])) ? OCSP_REVOKED_STATUS_UNSPECIFIED : $pconfig['crlreason'];
163
			cert_revoke($cert, $crl, $reason);
164
			// refresh IPsec and OpenVPN CRLs 
165
			openvpn_refresh_crls();
166
			vpn_ipsec_configure();
167
			write_config("Revoked cert {$cert['descr']} in CRL {$crl['descr']}.");
168
			pfSenseHeader("system_crlmanager.php");
169
			exit;
170
		}
171
	}
172
}
173

    
174
if ($act == "delcert") {
175
	if (!is_array($thiscrl['cert'])) {
176
		pfSenseHeader("system_crlmanager.php");
177
		exit;
178
	}
179
	$found = false;
180
	foreach ($thiscrl['cert'] as $acert) {
181
		if ($acert['refid'] == $_GET['certref']) {
182
			$found = true;
183
			$thiscert = $acert;
184
		}
185
	}
186
	if (!$found) {
187
		pfSenseHeader("system_crlmanager.php");
188
		exit;
189
	}
190
	$certname = htmlspecialchars($thiscert['descr']);
191
	$crlname = htmlspecialchars($thiscrl['descr']);
192
	if (cert_unrevoke($thiscert, $thiscrl)) {
193
		$savemsg = sprintf(gettext("Deleted Certificate %s from CRL %s"), $certname, $crlname) . "<br />";
194
		// refresh IPsec and OpenVPN CRLs 
195
		openvpn_refresh_crls();
196
		vpn_ipsec_configure();
197
		write_config(sprintf(gettext("Deleted Certificate %s from CRL %s"), $certname, $crlname));
198
	} else {
199
		$savemsg = sprintf(gettext("Failed to delete Certificate %s from CRL %s"), $certname, $crlname) . "<br />";
200
	}
201
	$act="edit";
202
}
203

    
204
if ($_POST) {
205
	$input_errors = array();
206
	$pconfig = $_POST;
207

    
208
	/* input validation */
209
	if (($pconfig['method'] == "existing") || ($act == "editimported")) {
210
		$reqdfields = explode(" ", "descr crltext");
211
		$reqdfieldsn = array(
212
			gettext("Descriptive name"),
213
			gettext("Certificate Revocation List data"));
214
	}
215
	if ($pconfig['method'] == "internal") {
216
		$reqdfields = explode(" ", "descr caref");
217
		$reqdfieldsn = array(
218
			gettext("Descriptive name"),
219
			gettext("Certificate Authority"));
220
	}
221

    
222
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
223

    
224
	if (preg_match("/[\?\>\<\&\/\\\"\']/", $pconfig['descr'])) {
225
		array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
226
	}
227

    
228
	/* if this is an AJAX caller then handle via JSON */
229
	if (isAjax() && is_array($input_errors)) {
230
		input_errors2Ajax($input_errors);
231
		exit;
232
	}
233

    
234
	/* save modifications */
235
	if (!$input_errors) {
236
		$result = false;
237

    
238
		if ($thiscrl) {
239
			$crl =& $thiscrl;
240
		} else {
241
			$crl = array();
242
			$crl['refid'] = uniqid();
243
		}
244

    
245
		$crl['descr'] = $pconfig['descr'];
246
		if ($act != "editimported") {
247
			$crl['caref'] = $pconfig['caref'];
248
			$crl['method'] = $pconfig['method'];
249
		}
250

    
251
		if (($pconfig['method'] == "existing") || ($act == "editimported")) {
252
			$crl['text'] = base64_encode($pconfig['crltext']);
253
		}
254

    
255
		if ($pconfig['method'] == "internal") {
256
			$crl['serial'] = empty($pconfig['serial']) ? 9999 : $pconfig['serial'];
257
			$crl['lifetime'] = empty($pconfig['lifetime']) ? 9999 : $pconfig['lifetime'];
258
			$crl['cert'] = array();
259
		}
260

    
261
		if (!$thiscrl) {
262
			$a_crl[] = $crl;
263
		}
264

    
265
		write_config("Saved CRL {$crl['descr']}");
266
		// refresh IPsec and OpenVPN CRLs 
267
		openvpn_refresh_crls();
268
		vpn_ipsec_configure();
269
		pfSenseHeader("system_crlmanager.php");
270
	}
271
}
272

    
273
include("head.inc");
274
?>
275

    
276
<script type="text/javascript">
277
//<![CDATA[
278

    
279
function method_change() {
280

    
281
	method = document.iform.method.value;
282

    
283
	switch (method) {
284
		case "internal":
285
			document.getElementById("existing").style.display="none";
286
			document.getElementById("internal").style.display="";
287
			break;
288
		case "existing":
289
			document.getElementById("existing").style.display="";
290
			document.getElementById("internal").style.display="none";
291
			break;
292
	}
293
}
294

    
295
//]]>
296
</script>
297

    
298
<?php
299

    
300
function build_method_list() {
301
	global $_GET, $crl_methods;
302
	
303
	$list = array();
304
	
305
	foreach($crl_methods as $method => $desc) {
306
		if (($_GET['importonly'] == "yes") && ($method != "existing"))
307
			continue;
308
			
309
		$list[$method] = $desc;
310
	}							
311
	
312
	return($list);		
313
}
314

    
315
function build_ca_list() {
316
	global $a_ca;
317
	
318
	$list = array();
319
	
320
	foreach($a_ca as $ca)
321
		$list[$ca['refid']] = $ca['descr'];
322

    
323
	return($list);
324
}
325

    
326
function build_cacert_list() {
327
	global $ca_certs;
328
	
329
	$list = array();
330

    
331
	foreach($ca_certs as $cert)
332
		$list[$cert['refid']] = $cert['descr']; 
333

    
334
	return($list);
335
}				
336

    
337
if ($input_errors)
338
	print_input_errors($input_errors);
339
	
340
if ($savemsg)
341
	print_info_box($savemsg, 'sucess');	
342
	
343
$tab_array = array();
344
$tab_array[] = array(gettext("CAs"), false, "system_camanager.php");
345
$tab_array[] = array(gettext("Certificates"), false, "system_certmanager.php");
346
$tab_array[] = array(gettext("Certificate Revocation"), true, "system_crlmanager.php");
347
display_top_tabs($tab_array);
348

    
349
require('classes/Form.class.php');
350

    
351
if ($act == "new" || $act == gettext("Save") || $input_errors) {
352
	if (!isset($id)) {
353
		$form = new Form();
354
		
355
		$section = new Form_Section('Create new revocation list');
356
		
357
		$section->addInput(new Form_Select(
358
			'method',
359
			'Method',
360
			$pconfig['method'],
361
			build_method_list()
362
		));
363
		
364
	}
365
	
366
	$section->addInput(new Form_Input(
367
		'descr',
368
		'Descriptive name',
369
		'text',
370
		$pconfig['descr']
371
	));
372

    
373
	$section->addInput(new Form_Select(
374
		'caref',
375
		'Certificate Authority',
376
		$pconfig['caref'],
377
		build_ca_list()
378
	));
379
		
380
	$form->add($section);
381
	
382
	$section = new Form_Section('Existing Certificate Revocation List');
383
	$section->addClass('existing');
384
	
385
	$section->addInput(new Form_Textarea(
386
		'crltext',
387
		'CRL data',
388
		$pconfig['crltext']
389
		))->setHelp('Paste a Certificate Revocation List in X.509 CRL format here.');
390
	
391
	$form->add($section);
392
	
393
	$section = new Form_Section('Internal Certificate Revocation List');
394
	$section->addClass('internal');
395
	
396
	$section->addInput(new Form_Input(
397
		'lifetime',
398
		'Lifetime (Days)',
399
		'number',
400
		$pconfig['lifetime'],
401
		[max => '9999']
402
	));
403
		
404
	$section->addInput(new Form_Input(
405
		'serial',
406
		'Serial',
407
		'number',
408
		$pconfig['serial'],
409
		[max => '9999']
410
	));
411
			
412
	$form->add($section);		
413
	
414
	if (isset($id) && $thiscrl) {
415
		$section->addInput(new Form_Input(
416
			'id',
417
			null,
418
			'hidden',
419
			$id
420
		));		
421
	}
422
									
423
	print($form);
424

    
425
} elseif ($act == "editimported") {
426
	
427
	$form = new Form();
428
		
429
	$section = new Form_Section('Edit Imported Certificate Revocation List');	
430
	
431
	$section->addInput(new Form_Input(
432
		'descr',
433
		'Descriptive name',
434
		'text',
435
		$pconfig['descr']
436
	));
437
	
438
	$section->addInput(new Form_Textarea(
439
		'crltext',
440
		'CRL data',
441
		$pconfig['crltext']
442
	))->setHelp('Paste a Certificate Revocation List in X.509 CRL format here.');
443
	
444
	$section->addInput(new Form_Input(
445
		'id',
446
		null,
447
		'hidden',
448
		$id
449
	));
450
	
451
	$section->addInput(new Form_Input(
452
		'act',
453
		null,
454
		'hidden',
455
		'editimported'
456
	));
457
											
458
	$form->add($section);
459
									
460
	print($form);
461
	
462
} elseif ($act == "edit") {
463
	$crl = $thiscrl;
464
	
465
	$form = new Form(false);
466
?>
467
	
468
	<div class="panel panel-default">
469
		<div class="panel-heading"><h2 class="panel-title"><?=gettext("Currently Revoked Certificates for CRL") . ': ' . $crl['descr']?></h2></div>
470
		<div class="panel-body table-responsive">
471
<?php		
472
	if (!is_array($crl['cert']) || (count($crl['cert']) == 0))
473
		print_info_box(gettext("No Certificates Found for this CRL."), 'danger');
474
	else {
475
?>	
476
			<table class="table table-striped table-hover table-condensed">
477
				<thead>
478
					<tr>
479
						<th><?=gettext("Certificate Name")?></th>
480
						<th><?=gettext("Revocation Reason")?></th>
481
						<th><?=gettext("Revoked At")?></th>
482
						<th></th>
483
					</tr>
484
				</thead>
485
				<tbody>
486
<?php				
487
		foreach($crl['cert'] as $i => $cert):
488
			$name = htmlspecialchars($cert['descr']);
489
?>
490
					<tr>
491
						<td class="listlr">
492
							<?=$name; ?>
493
						</td>
494
						<td class="listlr">
495
							<?=$openssl_crl_status[$cert["reason"]]; ?>
496
						</td>
497
						<td class="listlr">
498
							<?=date("D M j G:i:s T Y", $cert["revoke_time"]); ?>
499
						</td>
500
						<td class="list">
501
							<a href="system_crlmanager.php?act=delcert&amp;id=<?=$crl['refid']; ?>&amp;certref=<?=$cert['refid']; ?>" onclick="return confirm('<?=gettext("Do you really want to delete this Certificate from the CRL?")?>')">
502
								<img src="/themes/<?= $g['theme']?>/images/icons/icon_x.gif" title="<?=gettext("Delete this certificate from the CRL ")?>" alt="<?=gettext("Delete this certificate from the CRL ")?>" />
503
							</a>
504
						</td>
505
					</tr>
506
<?php
507
		endforeach;
508
?>
509
				</tbody>
510
			</table>
511
<?php } ?>			
512
		</div>
513
	</div>
514
<?php
515

    
516
	$ca_certs = array();
517
	foreach($a_cert as $cert)
518
		if ($cert['caref'] == $crl['caref'])
519
			$ca_certs[] = $cert;
520
			
521
	if (count($ca_certs) == 0)
522
		print_info_box(gettext("No Certificates Found for this CA."), 'danger');
523
	else
524
	
525
	$section = new Form_Section('Choose a certificate to revoke');
526
	$group = new Form_Group(null);
527
		
528
	$group->add(new Form_Select(
529
		'certref',
530
		null,
531
		$pconfig['certref'],
532
		build_cacert_list()	
533
		))->setWidth(4)->setHelp('Certificate');
534
		
535
	$group->add(new Form_Select(
536
		'crlreason',
537
		null,
538
		-1,
539
		$openssl_crl_status
540
		))->setHelp('Reason');
541
		
542
	$group->add(new Form_Button(
543
		'submit',
544
		'Add'
545
		))->removeClass('btn-primary')->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
	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">
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></th>
586
					</tr>
587
				</thead>
588
				<tbody>
589
<?php
590
	$caimg = "/themes/{$g['theme']}/images/icons/icon_frmfld_cert.png";
591
	// Map CRLs to CAs in one pass
592
	$ca_crl_map = array();
593
	foreach($a_crl as $crl)
594
		$ca_crl_map[$crl['caref']][] = $crl['refid'];
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
					<tr>
606
						<td colspan="4">
607
							<?=$name?>
608
						</td>
609
						<td>
610
<?php 
611
		if ($cainternal == "YES"): ?>
612
							<a href="system_crlmanager.php?act=new&amp;caref=<?=$ca['refid']; ?>" class="btn btn-xs btn-success">
613
								<?=gettext("Add or Import CRLl")?>
614
							</a>
615
<?php 
616
		else: ?>
617
							<a href="system_crlmanager.php?act=new&amp;caref=<?=$ca['refid']; ?>&amp;importonly=yes" class="btn btn-xs btn-success">
618
								<?=gettext("Add or Import CRLl")?>
619
							</a>							
620
<?php 
621
		endif; ?>
622
						</td>
623
					</tr>
624
<?php
625
		if (is_array($ca_crl_map[$ca['refid']])):
626
			foreach($ca_crl_map[$ca['refid']] as $crl):
627
				$tmpcrl = lookup_crl($crl);
628
				$internal = is_crl_internal($tmpcrl);
629
				$inuse = crl_in_use($tmpcrl['refid']);
630
?>
631
					<tr>
632
						<td><?=$tmpcrl['descr']; ?></td>
633
						<td><?=($internal) ? "YES" : "NO"; ?></td>
634
						<td><?=($internal) ? count($tmpcrl['cert']) : "Unknown (imported)"; ?></td>
635
						<td><?=($inuse) ? "YES" : "NO"; ?></td>
636
						<td>
637
							<a href="system_crlmanager.php?act=exp&amp;id=<?=$tmpcrl['refid']?>" class="btn btn-xs btn-success">
638
								<?=gettext("Export CRL")?>"
639
							</a>
640
<?php 
641
				if ($internal): ?>
642
							<a href="system_crlmanager.php?act=edit&amp;id=<?=$tmpcrl['refid']?>" class="btn btn-xs btn-info">
643
								<?=gettext("Edit CRL")?>
644
							</a>
645
<?php 
646
				else: ?>
647
							<a href="system_crlmanager.php?act=editimported&amp;id=<?=$tmpcrl['refid']?>" class="btn btn-xs btn-info">
648
								<?=gettext("Edit CRL")?>
649
							</a>
650
<?php 			endif;
651
				if (!$inuse): ?>
652
							<a href="system_crlmanager.php?act=del&amp;id=<?=$tmpcrl['refid']?>" class="btn btn-xs btn-danger">
653
								<?=gettext("Delete CRL")?>
654
							</a>
655
<?php 
656
				endif; ?>
657
						</td>
658
					</tr>
659
<?php
660
				$i++;
661
				endforeach;
662
			endif;
663
			$i++;
664
		endforeach;
665
?>						
666
				</tbody>
667
			</table>
668
		</div>
669
	</div>
670
					
671
					
672
<?php						
673
}
674
?>
675

    
676
<script>
677
//<![CDATA[   
678
events.push(function(){
679
    
680
    // Hides all elements of the specified class. This will usually be a section or group   
681
    function hideClass(s_class, hide) {
682
        if(hide)
683
            $('.' + s_class).hide();
684
        else
685
            $('.' + s_class).show();  
686
    }
687
    
688
    // When the 'method" selector is changed, we show/hide certain sections
689
    $('#method').on('change', function() {
690
    	hideClass('internal', ($('#method').val() == 'existing'));
691
    	hideClass('existing', ($('#method').val() == 'internal'));
692
    });
693
    
694
	hideClass('internal', ($('#method').val() == 'existing'));
695
	hideClass('existing', ($('#method').val() == 'internal'));
696
});
697
//]]>  
698
</script>
699

    
700
<?php include("foot.inc");
701

    
(197-197/238)