Project

General

Profile

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

    
45
global $openssl_crl_status;
46

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

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

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

    
59
if (!is_array($config['ca']))
60
	$config['ca'] = array();
61

    
62
$a_ca =& $config['ca'];
63

    
64
if (!is_array($config['cert']))
65
	$config['cert'] = array();
66

    
67
$a_cert =& $config['cert'];
68

    
69
if (!is_array($config['crl']))
70
	$config['crl'] = array();
71

    
72
$a_crl =& $config['crl'];
73

    
74
foreach ($a_crl as $cid => $acrl)
75
	if (!isset($acrl['refid']))
76
		unset ($a_crl[$cid]);
77

    
78
$act = $_GET['act'];
79

    
80
if ($_POST['act'])
81
	$act = $_POST['act'];
82

    
83

    
84
if (!empty($id))
85
	$thiscrl =& lookup_crl($id);
86

    
87
// If we were given an invalid crlref in the id, no sense in continuing as it would only cause errors.
88
if (!$thiscrl && (($act != "") && ($act != "new"))) {
89
	pfSenseHeader("system_crlmanager.php");
90
	$act="";
91
	$savemsg = gettext("Invalid CRL reference.");
92
}	
93

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

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

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

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

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

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

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

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

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

    
152
		if (!$input_errors) {
153
			$reason = (empty($pconfig['crlreason'])) ? OCSP_REVOKED_STATUS_UNSPECIFIED : $pconfig['crlreason'];
154
			cert_revoke($cert, $crl, $reason);
155
			openvpn_refresh_crls();
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
	$name = $thiscert['descr'];
180
	if (cert_unrevoke($thiscert, $thiscrl)) {
181
		$savemsg = sprintf(gettext("Deleted Certificate %s from CRL %s"), $name, $thiscrl['descr']) . "<br />";
182
		openvpn_refresh_crls();
183
		write_config(sprintf(gettext("Deleted Certificate %s from CRL %s"), $name, $thiscrl['descr']));
184
	} else {
185
		$savemsg = sprintf(gettext("Failed to delete Certificate %s from CRL %s"), $name, $thiscrl['descr']) . "<br />";
186
	}
187
	$act="edit";
188
}
189

    
190
if ($_POST) {
191
	unset($input_errors);
192
	$pconfig = $_POST;
193

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

    
209
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
210

    
211
	/* if this is an AJAX caller then handle via JSON */
212
	if (isAjax() && is_array($input_errors)) {
213
		input_errors2Ajax($input_errors);
214
		exit;
215
	}
216

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

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

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

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

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

    
244
		if (!$thiscrl)
245
			$a_crl[] = $crl;
246

    
247
		write_config("Saved CRL {$crl['descr']}");
248
		openvpn_refresh_crls();
249
		pfSenseHeader("system_crlmanager.php");
250
	}
251
}
252

    
253
include("head.inc");
254
?>
255

    
256
<script type="text/javascript">
257
//<![CDATA[
258

    
259
function method_change() {
260

    
261
	method = document.iform.method.value;
262

    
263
	switch (method) {
264
		case "internal":
265
			document.getElementById("existing").style.display="none";
266
			document.getElementById("internal").style.display="";
267
			break;
268
		case "existing":
269
			document.getElementById("existing").style.display="";
270
			document.getElementById("internal").style.display="none";
271
			break;
272
	}
273
}
274

    
275
//]]>
276
</script>
277

    
278
<?php
279

    
280
function build_method_list() {
281
	global $_GET, $crl_methods;
282
	
283
	$list = array();
284
	
285
	foreach($crl_methods as $method => $desc) {
286
		if (($_GET['importonly'] == "yes") && ($method != "existing"))
287
			continue;
288
			
289
		$list[$method] = $desc;
290
	}							
291
	
292
	return($list);		
293
}
294

    
295
function build_ca_list() {
296
	global $a_ca;
297
	
298
	$list = array();
299
	
300
	foreach($a_ca as $ca)
301
		$list[$ca['refid']] = $ca['descr'];
302

    
303
	return($list);
304
}
305

    
306
function build_cacert_list() {
307
	global $ca_certs;
308
	
309
	$list = array();
310

    
311
	foreach($ca_certs as $cert)
312
		$list[$cert['refid']] = $cert['descr']; 
313

    
314
	return($list);
315
}				
316

    
317
if ($input_errors)
318
	print_input_errors($input_errors);
319
	
320
if ($savemsg)
321
	print_info_box($savemsg, 'sucess');	
322
	
323
$tab_array = array();
324
$tab_array[] = array(gettext("CAs"), false, "system_camanager.php");
325
$tab_array[] = array(gettext("Certificates"), false, "system_certmanager.php");
326
$tab_array[] = array(gettext("Certificate Revocation"), true, "system_crlmanager.php");
327
display_top_tabs($tab_array);
328

    
329
require('classes/Form.class.php');
330

    
331
if ($act == "new" || $act == gettext("Save") || $input_errors) {
332
	if (!isset($id)) {
333
		$form = new Form();
334
		
335
		$section = new Form_Section('Create new revocation list');
336
		
337
		$section->addInput(new Form_Select(
338
			'method',
339
			'Method',
340
			$pconfig['method'],
341
			build_method_list()
342
		));
343
		
344
	}
345
	
346
	$section->addInput(new Form_Input(
347
		'descr',
348
		'Descriptive name',
349
		'text',
350
		$pconfig['descr']
351
	));
352

    
353
	$section->addInput(new Form_Select(
354
		'caref',
355
		'Certificate Authority',
356
		$pconfig['caref'],
357
		build_ca_list()
358
	));
359
		
360
	$form->add($section);
361
	
362
	$section = new Form_Section('Existing Certificate Revocation List');
363
	$section->addClass('existing');
364
	
365
	$section->addInput(new Form_Textarea(
366
		'crltext',
367
		'CRL data',
368
		$pconfig['crltext']
369
		))->setHelp('Paste a Certificate Revocation List in X.509 CRL format here.');
370
	
371
	$form->add($section);
372
	
373
	$section = new Form_Section('Internal Certificate Revocation List');
374
	$section->addClass('internal');
375
	
376
	$section->addInput(new Form_Input(
377
		'lifetime',
378
		'Lifetime (Days)',
379
		'number',
380
		$pconfig['lifetime'],
381
		[max => '9999']
382
	));
383
		
384
	$section->addInput(new Form_Input(
385
		'serial',
386
		'Serial',
387
		'number',
388
		$pconfig['serial'],
389
		[max => '9999']
390
	));
391
			
392
	$form->add($section);		
393
	
394
	if (isset($id) && $thiscrl) {
395
		$section->addInput(new Form_Input(
396
			'id',
397
			null,
398
			'hidden',
399
			$id
400
		));		
401
	}
402
									
403
	print($form);
404

    
405
} elseif ($act == "editimported") {
406
	
407
	$form = new Form();
408
		
409
	$section = new Form_Section('Edit Imported Certificate Revocation List');	
410
	
411
	$section->addInput(new Form_Input(
412
		'descr',
413
		'Descriptive name',
414
		'text',
415
		$pconfig['descr']
416
	));
417
	
418
	$section->addInput(new Form_Textarea(
419
		'crltext',
420
		'CRL data',
421
		$pconfig['crltext']
422
	))->setHelp('Paste a Certificate Revocation List in X.509 CRL format here.');
423
	
424
	$section->addInput(new Form_Input(
425
		'id',
426
		null,
427
		'hidden',
428
		$id
429
	));
430
	
431
	$section->addInput(new Form_Input(
432
		'act',
433
		null,
434
		'hidden',
435
		'editimported'
436
	));
437
											
438
	$form->add($section);
439
									
440
	print($form);
441
	
442
} elseif ($act == "edit") {
443
	$crl = $thiscrl;
444
	
445
	$form = new Form(false);
446
?>
447
	
448
	<div class="panel panel-default">
449
		<div class="panel-heading"><h2 class="panel-title"><?=gettext("Currently Revoked Certificates for CRL") . ': ' . $crl['descr']?></h2></div>
450
		<div class="panel-body table-responsive">
451
<?php		
452
	if (!is_array($crl['cert']) || (count($crl['cert']) == 0))
453
		print_info_box(gettext("No Certificates Found for this CRL."), 'danger');
454
	else {
455
?>	
456
			<table class="table table-striped table-hover table-condensed">
457
				<thead>
458
					<tr>
459
						<th><?=gettext("Certificate Name")?></th>
460
						<th><?=gettext("Revocation Reason")?></th>
461
						<th><?=gettext("Revoked At")?></th>
462
						<th></th>
463
					</tr>
464
				</thead>
465
				<tbody>
466
<?php				
467
		foreach($crl['cert'] as $i => $cert):
468
			$name = htmlspecialchars($cert['descr']);
469
?>
470
					<tr>
471
						<td class="listlr">
472
							<?=$name; ?>
473
						</td>
474
						<td class="listlr">
475
							<?=$openssl_crl_status[$cert["reason"]]; ?>
476
						</td>
477
						<td class="listlr">
478
							<?=date("D M j G:i:s T Y", $cert["revoke_time"]); ?>
479
						</td>
480
						<td class="list">
481
							<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?")?>')">
482
								<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 ")?>" />
483
							</a>
484
						</td>
485
					</tr>
486
<?php
487
		endforeach;
488
?>
489
				</tbody>
490
			</table>
491
<?php } ?>			
492
		</div>
493
	</div>
494
<?php
495

    
496
	$ca_certs = array();
497
	foreach($a_cert as $cert)
498
		if ($cert['caref'] == $crl['caref'])
499
			$ca_certs[] = $cert;
500
			
501
	if (count($ca_certs) == 0)
502
		print_info_box(gettext("No Certificates Found for this CA."), 'danger');
503
	else
504
	
505
	$section = new Form_Section('Choose a certificate to revoke');
506
	$group = new Form_Group(null);
507
		
508
	$group->add(new Form_Select(
509
		'certref',
510
		null,
511
		$pconfig['certref'],
512
		build_cacert_list()	
513
		))->setWidth(4)->setHelp('Certificate');
514
		
515
	$group->add(new Form_Select(
516
		'crlreason',
517
		null,
518
		-1,
519
		$openssl_crl_status
520
		))->setHelp('Reason');
521
		
522
	$group->add(new Form_Button(
523
		'submit',
524
		'Add'
525
		))->removeClass('btn-primary')->addClass('btn-success btn-sm');
526
		
527
	$section->add($group);
528
	
529
	$section->addInput(new Form_Input(
530
		'id',
531
		null,
532
		'hidden',
533
		$crl['refid']
534
	));
535
	
536
	$section->addInput(new Form_Input(
537
		'act',
538
		null,
539
		'hidden',
540
		'addcert'
541
	));
542
	
543
	$section->addInput(new Form_Input(
544
		'crlref',
545
		null,
546
		'hidden',
547
		$crl['refid']
548
	));
549
			
550
	$form->add($section);
551
	print($form);
552
} else {
553
?>
554

    
555
	<div class="panel panel-default">
556
		<div class="panel-heading"><h2 class="panel-title"><?=gettext("Additional Certificate Revocation Lists")?></h2></div>
557
		<div class="panel-body table-responsive">
558
			<table class="table table-striped table-hover table-condensed">
559
				<thead>
560
					<tr>
561
						<th><?=gettext("Name")?></th>
562
						<th><?=gettext("Internal")?></th>
563
						<th><?=gettext("Certificates")?></th>
564
						<th><?=gettext("In Use")?></th>
565
						<th></th>
566
					</tr>
567
				</thead>
568
				<tbody>
569
<?php
570
	$caimg = "/themes/{$g['theme']}/images/icons/icon_frmfld_cert.png";
571
	// Map CRLs to CAs in one pass
572
	$ca_crl_map = array();
573
	foreach($a_crl as $crl)
574
		$ca_crl_map[$crl['caref']][] = $crl['refid'];
575

    
576
	$i = 0;
577
	foreach($a_ca as $ca):
578
		$name = htmlspecialchars($ca['descr']);
579

    
580
		if($ca['prv']) {
581
			$cainternal = "YES";
582
		} else 
583
			$cainternal = "NO";
584
?>				
585
					<tr>
586
						<td colspan="4">
587
							<?=$name?>
588
						</td>
589
						<td>
590
<?php 
591
		if ($cainternal == "YES"): ?>
592
							<a href="system_crlmanager.php?act=new&amp;caref=<?=$ca['refid']; ?>" class="btn btn-xs btn-success">
593
								<?=gettext("Add or Import CRLl")?>
594
							</a>
595
<?php 
596
		else: ?>
597
							<a href="system_crlmanager.php?act=new&amp;caref=<?=$ca['refid']; ?>&amp;importonly=yes" class="btn btn-xs btn-success">
598
								<?=gettext("Add or Import CRLl")?>
599
							</a>							
600
<?php 
601
		endif; ?>
602
						</td>
603
					</tr>
604
<?php
605
		if (is_array($ca_crl_map[$ca['refid']])):
606
			foreach($ca_crl_map[$ca['refid']] as $crl):
607
				$tmpcrl = lookup_crl($crl);
608
				$internal = is_crl_internal($tmpcrl);
609
				$inuse = crl_in_use($tmpcrl['refid']);
610
?>
611
					<tr>
612
						<td><?=$tmpcrl['descr']; ?></td>
613
						<td><?=($internal) ? "YES" : "NO"; ?></td>
614
						<td><?=($internal) ? count($tmpcrl['cert']) : "Unknown (imported)"; ?></td>
615
						<td><?=($inuse) ? "YES" : "NO"; ?></td>
616
						<td>
617
							<a href="system_crlmanager.php?act=exp&amp;id=<?=$tmpcrl['refid']?>" class="btn btn-xs btn-success">
618
								<?=gettext("Export CRL")?>"
619
							</a>
620
<?php 
621
				if ($internal): ?>
622
							<a href="system_crlmanager.php?act=edit&amp;id=<?=$tmpcrl['refid']?>" class="btn btn-xs btn-info">
623
								<?=gettext("Edit CRL")?>
624
							</a>
625
<?php 
626
				else: ?>
627
							<a href="system_crlmanager.php?act=editimported&amp;id=<?=$tmpcrl['refid']?>" class="btn btn-xs btn-info">
628
								<?=gettext("Edit CRL")?>
629
							</a>
630
<?php 			endif;
631
				if (!$inuse): ?>
632
							<a href="system_crlmanager.php?act=del&amp;id=<?=$tmpcrl['refid']?>" class="btn btn-xs btn-danger">
633
								<?=gettext("Delete CRL")?>
634
							</a>
635
<?php 
636
				endif; ?>
637
						</td>
638
					</tr>
639
<?php
640
				$i++;
641
				endforeach;
642
			endif;
643
			$i++;
644
		endforeach;
645
?>						
646
				</tbody>
647
			</table>
648
		</div>
649
	</div>
650
					
651
					
652
<?php						
653
}
654
?>
655

    
656
<script>
657
//<![CDATA[   
658
events.push(function(){
659
    
660
    // Hides all elements of the specified class. This will usually be a section or group   
661
    function hideClass(s_class, hide) {
662
        if(hide)
663
            $('.' + s_class).hide();
664
        else
665
            $('.' + s_class).show();  
666
    }
667
    
668
    // When the 'method" selector is changed, we show/hide certain sections
669
    $('#method').on('change', function() {
670
    	hideClass('internal', ($('#method').val() == 'existing'));
671
    	hideClass('existing', ($('#method').val() == 'internal'));
672
    });
673
    
674
	hideClass('internal', ($('#method').val() == 'existing'));
675
	hideClass('existing', ($('#method').val() == 'internal'));
676
});
677
//]]>  
678
</script>
679

    
680
<?php include("foot.inc");
681

    
(196-196/237)