Project

General

Profile

Download (28.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	system_certmanager.php
4
*/
5
/* ====================================================================
6
 *	Copyright (c)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved.
7
 *	Copyright (c)  2004, 2005 Scott Ullrich
8
 *	Copyright (c)  2008 Shrew Soft Inc.
9
 *
10
 *	Redistribution and use in source and binary forms, with or without modification,
11
 *	are permitted provided that the following conditions are met:
12
 *
13
 *	1. Redistributions of source code must retain the above copyright notice,
14
 *		this list of conditions and the following disclaimer.
15
 *
16
 *	2. Redistributions in binary form must reproduce the above copyright
17
 *		notice, this list of conditions and the following disclaimer in
18
 *		the documentation and/or other materials provided with the
19
 *		distribution.
20
 *
21
 *	3. All advertising materials mentioning features or use of this software
22
 *		must display the following acknowledgment:
23
 *		"This product includes software developed by the pfSense Project
24
 *		 for use in the pfSense software distribution. (http://www.pfsense.org/).
25
 *
26
 *	4. The names "pfSense" and "pfSense Project" must not be used to
27
 *		 endorse or promote products derived from this software without
28
 *		 prior written permission. For written permission, please contact
29
 *		 coreteam@pfsense.org.
30
 *
31
 *	5. Products derived from this software may not be called "pfSense"
32
 *		nor may "pfSense" appear in their names without prior written
33
 *		permission of the Electric Sheep Fencing, LLC.
34
 *
35
 *	6. Redistributions of any form whatsoever must retain the following
36
 *		acknowledgment:
37
 *
38
 *	"This product includes software developed by the pfSense Project
39
 *	for use in the pfSense software distribution (http://www.pfsense.org/).
40
 *
41
 *	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
42
 *	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43
 *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
44
 *	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
45
 *	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46
 *	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47
 *	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
48
 *	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49
 *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
50
 *	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51
 *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
52
 *	OF THE POSSIBILITY OF SUCH DAMAGE.
53
 *
54
 *	====================================================================
55
 *
56
 */
57
/*
58
	pfSense_MODULE: certificate_manager
59
*/
60

    
61
##|+PRIV
62
##|*IDENT=page-system-certmanager
63
##|*NAME=System: Certificate Manager
64
##|*DESCR=Allow access to the 'System: Certificate Manager' page.
65
##|*MATCH=system_certmanager.php*
66
##|-PRIV
67

    
68
require("guiconfig.inc");
69
require_once("certs.inc");
70

    
71
$cert_methods = array(
72
	"import" => gettext("Import an existing Certificate"),
73
	"internal" => gettext("Create an internal Certificate"),
74
	"external" => gettext("Create a Certificate Signing Request"),
75
);
76

    
77
$cert_keylens = array("512", "1024", "2048", "4096");
78
$cert_types = array(
79
	"ca" => "Certificate Authority",
80
	"server" => "Server Certificate",
81
	"user" => "User Certificate");
82

    
83
$altname_types = array("DNS", "IP", "email", "URI");
84
$openssl_digest_algs = array("sha1", "sha224", "sha256", "sha384", "sha512");
85

    
86
$pgtitle = array(gettext("System"), gettext("Certificate Manager"));
87

    
88
if (is_numericint($_GET['userid'])) {
89
	$userid = $_GET['userid'];
90
}
91
if (isset($_POST['userid']) && is_numericint($_POST['userid'])) {
92
	$userid = $_POST['userid'];
93
}
94

    
95
if (isset($userid)) {
96
	$cert_methods["existing"] = gettext("Choose an existing certificate");
97
	if (!is_array($config['system']['user'])) {
98
		$config['system']['user'] = array();
99
	}
100
	$a_user =& $config['system']['user'];
101
}
102

    
103
if (is_numericint($_GET['id'])) {
104
	$id = $_GET['id'];
105
}
106
if (isset($_POST['id']) && is_numericint($_POST['id'])) {
107
	$id = $_POST['id'];
108
}
109

    
110
if (!is_array($config['ca'])) {
111
	$config['ca'] = array();
112
}
113

    
114
$a_ca =& $config['ca'];
115

    
116
if (!is_array($config['cert'])) {
117
	$config['cert'] = array();
118
}
119

    
120
$a_cert =& $config['cert'];
121

    
122
$internal_ca_count = 0;
123
foreach ($a_ca as $ca) {
124
	if ($ca['prv']) {
125
		$internal_ca_count++;
126
	}
127
}
128

    
129
$act = $_GET['act'];
130

    
131
if ($_POST['act']) {
132
	$act = $_POST['act'];
133
}
134

    
135
if ($act == "del") {
136

    
137
	if (!isset($a_cert[$id])) {
138
		pfSenseHeader("system_certmanager.php");
139
		exit;
140
	}
141

    
142
	unset($a_cert[$id]);
143
	write_config();
144
	$savemsg = sprintf(gettext("Certificate %s successfully deleted"), htmlspecialchars($a_cert[$id]['descr'])) . "<br />";
145
	pfSenseHeader("system_certmanager.php");
146
	exit;
147
}
148

    
149

    
150
if ($act == "new") {
151
	$pconfig['method'] = $_GET['method'];
152
	$pconfig['keylen'] = "2048";
153
	$pconfig['digest_alg'] = "sha256";
154
	$pconfig['csr_keylen'] = "2048";
155
	$pconfig['csr_digest_alg'] = "sha256";
156
	$pconfig['type'] = "user";
157
	$pconfig['lifetime'] = "3650";
158
}
159

    
160
if ($act == "exp") {
161

    
162
	if (!$a_cert[$id]) {
163
		pfSenseHeader("system_certmanager.php");
164
		exit;
165
	}
166

    
167
	$exp_name = urlencode("{$a_cert[$id]['descr']}.crt");
168
	$exp_data = base64_decode($a_cert[$id]['crt']);
169
	$exp_size = strlen($exp_data);
170

    
171
	header("Content-Type: application/octet-stream");
172
	header("Content-Disposition: attachment; filename={$exp_name}");
173
	header("Content-Length: $exp_size");
174
	echo $exp_data;
175
	exit;
176
}
177

    
178
if ($act == "key") {
179

    
180
	if (!$a_cert[$id]) {
181
		pfSenseHeader("system_certmanager.php");
182
		exit;
183
	}
184

    
185
	$exp_name = urlencode("{$a_cert[$id]['descr']}.key");
186
	$exp_data = base64_decode($a_cert[$id]['prv']);
187
	$exp_size = strlen($exp_data);
188

    
189
	header("Content-Type: application/octet-stream");
190
	header("Content-Disposition: attachment; filename={$exp_name}");
191
	header("Content-Length: $exp_size");
192
	echo $exp_data;
193
	exit;
194
}
195

    
196
if ($act == "p12") {
197
	if (!$a_cert[$id]) {
198
		pfSenseHeader("system_certmanager.php");
199
		exit;
200
	}
201

    
202
	$exp_name = urlencode("{$a_cert[$id]['descr']}.p12");
203
	$args = array();
204
	$args['friendly_name'] = $a_cert[$id]['descr'];
205

    
206
	$ca = lookup_ca($a_cert[$id]['caref']);
207
	if ($ca) {
208
		$args['extracerts'] = openssl_x509_read(base64_decode($ca['crt']));
209
	}
210

    
211
	$res_crt = openssl_x509_read(base64_decode($a_cert[$id]['crt']));
212
	$res_key = openssl_pkey_get_private(array(0 => base64_decode($a_cert[$id]['prv']) , 1 => ""));
213

    
214
	$exp_data = "";
215
	openssl_pkcs12_export($res_crt, $exp_data, $res_key, null, $args);
216
	$exp_size = strlen($exp_data);
217

    
218
	header("Content-Type: application/octet-stream");
219
	header("Content-Disposition: attachment; filename={$exp_name}");
220
	header("Content-Length: $exp_size");
221
	echo $exp_data;
222
	exit;
223
}
224

    
225
if ($act == "csr") {
226

    
227
	if (!$a_cert[$id]) {
228
		pfSenseHeader("system_certmanager.php");
229
		exit;
230
	}
231

    
232
	$pconfig['descr'] = $a_cert[$id]['descr'];
233
	$pconfig['csr'] = base64_decode($a_cert[$id]['csr']);
234
}
235

    
236
if ($_POST) {
237
	if ($_POST['save'] == gettext("Save")) {
238
		$input_errors = array();
239
		$pconfig = $_POST;
240

    
241
		/* input validation */
242
		if ($pconfig['method'] == "import") {
243
			$reqdfields = explode(" ",
244
				"descr cert key");
245
			$reqdfieldsn = array(
246
				gettext("Descriptive name"),
247
				gettext("Certificate data"),
248
				gettext("Key data"));
249
			if ($_POST['cert'] && (!strstr($_POST['cert'], "BEGIN CERTIFICATE") || !strstr($_POST['cert'], "END CERTIFICATE"))) {
250
				$input_errors[] = gettext("This certificate does not appear to be valid.");
251
			}
252
		}
253

    
254
		if ($pconfig['method'] == "internal") {
255
			$reqdfields = explode(" ",
256
				"descr caref keylen type lifetime dn_country dn_state dn_city ".
257
				"dn_organization dn_email dn_commonname");
258
			$reqdfieldsn = array(
259
				gettext("Descriptive name"),
260
				gettext("Certificate authority"),
261
				gettext("Key length"),
262
				gettext("Certificate Type"),
263
				gettext("Lifetime"),
264
				gettext("Distinguished name Country Code"),
265
				gettext("Distinguished name State or Province"),
266
				gettext("Distinguished name City"),
267
				gettext("Distinguished name Organization"),
268
				gettext("Distinguished name Email Address"),
269
				gettext("Distinguished name Common Name"));
270
		}
271

    
272
		if ($pconfig['method'] == "external") {
273
			$reqdfields = explode(" ",
274
				"descr csr_keylen csr_dn_country csr_dn_state csr_dn_city ".
275
				"csr_dn_organization csr_dn_email csr_dn_commonname");
276
			$reqdfieldsn = array(
277
				gettext("Descriptive name"),
278
				gettext("Key length"),
279
				gettext("Distinguished name Country Code"),
280
				gettext("Distinguished name State or Province"),
281
				gettext("Distinguished name City"),
282
				gettext("Distinguished name Organization"),
283
				gettext("Distinguished name Email Address"),
284
				gettext("Distinguished name Common Name"));
285
		}
286

    
287
		if ($pconfig['method'] == "existing") {
288
			$reqdfields = array("certref");
289
			$reqdfieldsn = array(gettext("Existing Certificate Choice"));
290
		}
291

    
292
		$altnames = array();
293
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
294
		if ($pconfig['method'] != "import" && $pconfig['method'] != "existing") {
295
			/* subjectAltNames */
296
			foreach ($_POST['altname_value'] as $idx => $value) {
297
				if (empty($value))
298
					continue;
299

    
300
				$altnames[$idx] = array(
301
					'type' => $_POST['altname_type'][$idx],
302
					'value' => $value
303
				);
304
			}
305
			$pconfig['altnames']['item'] = $altnames;
306

    
307
			/* Input validation for subjectAltNames */
308
			foreach ($altnames as $idx => $altname) {
309
				switch ($altname['type']) {
310
					case "DNS":
311
						if (!is_hostname($altname['value'])) {
312
							array_push($input_errors, "DNS subjectAltName values must be valid hostnames or FQDNs");
313
						}
314
						break;
315
					case "IP":
316
						if (!is_ipaddr($altname['value'])) {
317
							array_push($input_errors, "IP subjectAltName values must be valid IP Addresses");
318
						}
319
						break;
320
					case "email":
321
						if (empty($altname['value'])) {
322
							array_push($input_errors, "You must provide an e-mail address for this type of subjectAltName");
323
						}
324
						if (preg_match("/[\!\#\$\%\^\(\)\~\?\>\<\&\/\\\,\"\']/", $altname['value'])) {
325
							array_push($input_errors, "The e-mail provided in a subjectAltName contains invalid characters.");
326
						}
327
						break;
328
					case "URI":
329
						/* Close enough? */
330
						if (!is_URL($altname['value'])) {
331
							$input_errors[] = "URI subjectAltName types must be a valid URI";
332
						}
333
						break;
334
					default:
335
						$input_errors[] = "Unrecognized subjectAltName type.";
336
				}
337
			}
338

    
339
			/* Make sure we do not have invalid characters in the fields for the certificate */
340

    
341
			if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
342
				array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
343
			}
344

    
345
			for ($i = 0; $i < count($reqdfields); $i++) {
346
				if (preg_match('/email/', $reqdfields[$i])) { /* dn_email or csr_dn_name */
347
					if (preg_match("/[\!\#\$\%\^\(\)\~\?\>\<\&\/\\\,\"\']/", $_POST[$reqdfields[$i]])) {
348
						array_push($input_errors, "The field 'Distinguished name Email Address' contains invalid characters.");
349
					}
350
				} else if (preg_match('/commonname/', $reqdfields[$i])) { /* dn_commonname or csr_dn_commonname */
351
					if (preg_match("/[\!\@\#\$\%\^\(\)\~\?\>\<\&\/\\\,\"\']/", $_POST[$reqdfields[$i]])) {
352
						array_push($input_errors, "The field 'Distinguished name Common Name' contains invalid characters.");
353
					}
354
				} else if (($reqdfields[$i] != "descr") && preg_match("/[\!\@\#\$\%\^\(\)\~\?\>\<\&\/\\\,\.\"\']/", $_POST[$reqdfields[$i]])) {
355
					array_push($input_errors, "The field '" . $reqdfieldsn[$i] . "' contains invalid characters.");
356
				}
357
			}
358

    
359
			if (($pconfig['method'] != "external") && isset($_POST["keylen"]) && !in_array($_POST["keylen"], $cert_keylens)) {
360
				array_push($input_errors, gettext("Please select a valid Key Length."));
361
			}
362
			if (($pconfig['method'] != "external") && !in_array($_POST["digest_alg"], $openssl_digest_algs)) {
363
				array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
364
			}
365

    
366
			if (($pconfig['method'] == "external") && isset($_POST["csr_keylen"]) && !in_array($_POST["csr_keylen"], $cert_keylens)) {
367
				array_push($input_errors, gettext("Please select a valid Key Length."));
368
			}
369
			if (($pconfig['method'] == "external") && !in_array($_POST["csr_digest_alg"], $openssl_digest_algs)) {
370
				array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
371
			}
372
		}
373

    
374
		/* if this is an AJAX caller then handle via JSON */
375
		if (isAjax() && is_array($input_errors)) {
376
			input_errors2Ajax($input_errors);
377
			exit;
378
		}
379

    
380
		/* save modifications */
381
		if (!$input_errors) {
382

    
383
			if ($pconfig['method'] == "existing") {
384
				$cert = lookup_cert($pconfig['certref']);
385
				if ($cert && $a_user) {
386
					$a_user[$userid]['cert'][] = $cert['refid'];
387
				}
388
			} else {
389
				$cert = array();
390
				$cert['refid'] = uniqid();
391
				if (isset($id) && $a_cert[$id]) {
392
					$cert = $a_cert[$id];
393
				}
394

    
395
				$cert['descr'] = $pconfig['descr'];
396

    
397
				$old_err_level = error_reporting(0); /* otherwise openssl_ functions throw warnings directly to a page screwing menu tab */
398

    
399
				if ($pconfig['method'] == "import") {
400
					cert_import($cert, $pconfig['cert'], $pconfig['key']);
401
				}
402

    
403
				if ($pconfig['method'] == "internal") {
404
					$dn = array(
405
						'countryName' => $pconfig['dn_country'],
406
						'stateOrProvinceName' => $pconfig['dn_state'],
407
						'localityName' => $pconfig['dn_city'],
408
						'organizationName' => $pconfig['dn_organization'],
409
						'emailAddress' => $pconfig['dn_email'],
410
						'commonName' => $pconfig['dn_commonname']);
411
					if (count($altnames)) {
412
						$altnames_tmp = "";
413
						foreach ($altnames as $altname) {
414
							$altnames_tmp[] = "{$altname['type']}:{$altname['value']}";
415
						}
416
						$dn['subjectAltName'] = implode(",", $altnames_tmp);
417
					}
418
					if (!cert_create($cert, $pconfig['caref'], $pconfig['keylen'],
419
						$pconfig['lifetime'], $dn, $pconfig['type'], $pconfig['digest_alg'])) {
420
						while ($ssl_err = openssl_error_string()) {
421
							$input_errors = array();
422
							array_push($input_errors, "openssl library returns: " . $ssl_err);
423
						}
424
					}
425
				}
426

    
427
				if ($pconfig['method'] == "external") {
428
					$dn = array(
429
						'countryName' => $pconfig['csr_dn_country'],
430
						'stateOrProvinceName' => $pconfig['csr_dn_state'],
431
						'localityName' => $pconfig['csr_dn_city'],
432
						'organizationName' => $pconfig['csr_dn_organization'],
433
						'emailAddress' => $pconfig['csr_dn_email'],
434
						'commonName' => $pconfig['csr_dn_commonname']);
435
					if (count($altnames)) {
436
						$altnames_tmp = "";
437
						foreach ($altnames as $altname) {
438
							$altnames_tmp[] = "{$altname['type']}:{$altname['value']}";
439
						}
440
						$dn['subjectAltName'] = implode(",", $altnames_tmp);
441
					}
442
					if (!csr_generate($cert, $pconfig['csr_keylen'], $dn, $pconfig['csr_digest_alg'])) {
443
						while ($ssl_err = openssl_error_string()) {
444
							$input_errors = array();
445
							array_push($input_errors, "openssl library returns: " . $ssl_err);
446
						}
447
					}
448
				}
449
				error_reporting($old_err_level);
450

    
451
				if (isset($id) && $a_cert[$id]) {
452
					$a_cert[$id] = $cert;
453
				} else {
454
					$a_cert[] = $cert;
455
				}
456
				if (isset($a_user) && isset($userid)) {
457
					$a_user[$userid]['cert'][] = $cert['refid'];
458
				}
459
			}
460

    
461
			if (!$input_errors) {
462
				write_config();
463
			}
464

    
465
			if ($userid) {
466
				post_redirect("system_usermanager.php", array('act' => 'edit', 'userid' => $userid));
467
				exit;
468
			}
469
		}
470
	}
471

    
472
	if ($_POST['save'] == gettext("Update")) {
473
		unset($input_errors);
474
		$pconfig = $_POST;
475

    
476
		/* input validation */
477
		$reqdfields = explode(" ", "descr cert");
478
		$reqdfieldsn = array(
479
		gettext("Descriptive name"),
480
		gettext("Final Certificate data"));
481

    
482
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
483

    
484
		if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
485
			array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
486
		}
487

    
488
//		old way
489
		/* make sure this csr and certificate subjects match */
490
//		$subj_csr = csr_get_subject($pconfig['csr'], false);
491
//		$subj_cert = cert_get_subject($pconfig['cert'], false);
492
//
493
//		if (!isset($_POST['ignoresubjectmismatch']) && !($_POST['ignoresubjectmismatch'] == "yes")) {
494
//			if (strcmp($subj_csr, $subj_cert)) {
495
//				$input_errors[] = sprintf(gettext("The certificate subject '%s' does not match the signing request subject."), $subj_cert);
496
//				$subject_mismatch = true;
497
//			}
498
//		}
499
		$mod_csr = csr_get_modulus($pconfig['csr'], false);
500
		$mod_cert = cert_get_modulus($pconfig['cert'], false);
501

    
502
		if (strcmp($mod_csr, $mod_cert)) {
503
			// simply: if the moduli don't match, then the private key and public key won't match
504
			$input_errors[] = sprintf(gettext("The certificate modulus does not match the signing request modulus."), $subj_cert);
505
			$subject_mismatch = true;
506
		}
507

    
508
		/* if this is an AJAX caller then handle via JSON */
509
		if (isAjax() && is_array($input_errors)) {
510
			input_errors2Ajax($input_errors);
511
			exit;
512
		}
513

    
514
		/* save modifications */
515
		if (!$input_errors) {
516

    
517
			$cert = $a_cert[$id];
518

    
519
			$cert['descr'] = $pconfig['descr'];
520

    
521
			csr_complete($cert, $pconfig['cert']);
522

    
523
			$a_cert[$id] = $cert;
524

    
525
			write_config();
526

    
527
			pfSenseHeader("system_certmanager.php");
528
		}
529
	}
530
}
531

    
532
include("head.inc");
533

    
534
if ($input_errors)
535
	print_input_errors($input_errors);
536
if ($savemsg)
537
	print_info_box($savemsg);
538

    
539
$tab_array = array();
540
$tab_array[] = array(gettext("CAs"), false, "system_camanager.php");
541
$tab_array[] = array(gettext("Certificates"), true, "system_certmanager.php");
542
$tab_array[] = array(gettext("Certificate Revocation"), false, "system_crlmanager.php");
543
display_top_tabs($tab_array);
544

    
545
// Load valid country codes
546
$dn_cc = array();
547
if (file_exists("/etc/ca_countries")){
548
	$dn_cc_file=file("/etc/ca_countries");
549
	foreach($dn_cc_file as $line) {
550
		if (preg_match('/^(\S*)\s(.*)$/', $line, $matches)) {
551
			$dn_cc[$matches[1]] = $matches[1];
552
		}
553
	}
554
}
555

    
556
if (!($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)))
557
{
558
?>
559
<div class="table-responsive">
560
<table class="table table-striped table-hover">
561
	<thead>
562
		<tr>
563
			<th><?=gettext("Name")?></th>
564
			<th><?=gettext("Issuer")?></th>
565
			<th><?=gettext("Distinguished Name")?></th>
566
			<th><?=gettext("In Use")?></th>
567
			<th></th>
568
		</tr>
569
	</thead>
570
	<tbody>
571
<?php
572
foreach($a_cert as $i => $cert):
573
	$name = htmlspecialchars($cert['descr']);
574

    
575
	if ($cert['crt']) {
576
		$subj = cert_get_subject($cert['crt']);
577
		$issuer = cert_get_issuer($cert['crt']);
578
		$purpose = cert_get_purpose($cert['crt']);
579
		list($startdate, $enddate) = cert_get_dates($cert['crt']);
580

    
581
		if ($subj==$issuer)
582
			$caname = '<i>'. gettext("self-signed") .'</i>';
583
		else
584
			$caname = '<i>'. gettext("external").'</i>';
585

    
586
		$subj = htmlspecialchars($subj);
587
	}
588

    
589
	if ($cert['csr']) {
590
		$subj = htmlspecialchars(csr_get_subject($cert['csr']));
591
		$caname = "<em>" . gettext("external - signature pending") . "</em>";
592
	}
593

    
594
	$ca = lookup_ca($cert['caref']);
595
	if ($ca)
596
		$caname = $ca['descr'];
597
?>
598
		<tr>
599
			<td>
600
				<?=$name?><br />
601
				<?php if ($cert['type']): ?>
602
					<i><?=$cert_types[$cert['type']]?></i><br />
603
				<?php endif?>
604
				<?php if (is_array($purpose)): ?>
605
					CA: <b><?=$purpose['ca']?></b>, Server: <b><?=$purpose['server']?></b>
606
				<?php endif?>
607
			</td>
608
			<td><?=$caname?></td>
609
			<td>
610
				<?=$subj?>
611
				<br />
612
				<small>
613
					<?=gettext("Valid From")?>: <b><?=$startdate ?></b><br /><?=gettext("Valid Until")?>: <b><?=$enddate ?></b>
614
				</small>
615
			</td>
616
			<td>
617
				<?php if (is_cert_revoked($cert)): ?>
618
					<i>Revoked </i>
619
				<?php endif?>
620
				<?php if (is_webgui_cert($cert['refid'])): ?>
621
					webConfigurator
622
				<?php endif?>
623
				<?php if (is_user_cert($cert['refid'])): ?>
624
					User Cert
625
				<?php endif?>
626
				<?php if (is_openvpn_server_cert($cert['refid'])): ?>
627
					OpenVPN Server
628
				<?php endif?>
629
				<?php if (is_openvpn_client_cert($cert['refid'])): ?>
630
					OpenVPN Client
631
				<?php endif?>
632
				<?php if (is_ipsec_cert($cert['refid'])): ?>
633
					IPsec Tunnel
634
				<?php endif?>
635
				<?php if (is_captiveportal_cert($cert['refid'])): ?>
636
					Captive Portal
637
				<?php endif?>
638
			</td>
639
			<td>
640
				<a href="system_certmanager.php?act=exp&amp;id=<?=$i?>" class="btn btn-xs btn-default">
641
					<?=gettext("export")?>
642
				</a>
643
				<a href="system_certmanager.php?act=key&amp;id=<?=$i?>" class="btn btn-xs btn-default">
644
					<?=gettext("export key")?>
645
				</a>
646
				<a href="system_certmanager.php?act=p12&amp;id=<?=$i?>" class="btn btn-xs btn-default">
647
					<?=gettext("export p12")?>
648
				</a>
649
				<?php if (!cert_in_use($cert['refid'])): ?>
650
					<a href="system_certmanager.php?act=del&amp;id=<?=$i?>" class="btn btn-xs btn-danger">
651
						<?=gettext("delete")?>
652
					</a>
653
				<?php endif?>
654
				<?php if ($cert['csr']): ?>
655
					<a href="system_certmanager.php?act=csr&amp;id=<?=$i?>" class="btn btn-xs btn-default">
656
						<?=gettext("update csr")?>
657
					</a>
658
				<?php endif?>
659
			</td>
660
		</tr>
661
<?php endforeach; ?>
662
	</tbody>
663
</table>
664
</div>
665

    
666
<nav class="action-buttons">
667
	<a href="?act=new" class="btn btn-success">add new</a>
668
</nav>
669
<?
670
	include("foot.inc");
671
	exit;
672
}
673

    
674
require_once('classes/Form.class.php');
675
$form = new Form;
676

    
677
if ($act == "csr" || (($_POST['save'] == gettext("Update")) && $input_errors))
678
{
679
	$form->setAction('system_certmanager.php?act=csr');
680

    
681
	$section = new Form_Section('Complete Signing Request');
682

    
683
	if (isset($id) && $a_cert[$id])
684
	{
685
		$form->addGlobal(new Form_Input(
686
			'id',
687
			null,
688
			'hidden',
689
			$id
690
		));
691
	}
692

    
693
	$section->addInput(new Form_Input(
694
		'descr',
695
		'Descriptive name',
696
		'text',
697
		$pconfig['descr']
698
	));
699

    
700
	$section->addInput(new Form_Textarea(
701
		'csr',
702
		'Signing request data',
703
		$pconfig['csr']
704
	))->setReadonly()->setHelp('Copy the certificate signing data from here and '.
705
		'forward it to your certificate authority for signing.');
706

    
707
	$section->addInput(new Form_Textarea(
708
		'cert',
709
		'Final certificate data',
710
		$pconfig["cert"]
711
	))->setHelp('Paste the certificate received from your certificate authority here.');
712

    
713
	$form->add($section);
714
	print $form;
715

    
716
	include("foot.inc");
717
	exit;
718
}
719

    
720
$form->setAction('system_certmanager.php?act=edit');
721

    
722
if (isset($userid) && $a_user)
723
{
724
	$form->addGlobal(new Form_Input(
725
		'userid',
726
		null,
727
		'hidden',
728
		$userid
729
	));
730
}
731

    
732
if (isset($id) && $a_cert[$id])
733
{
734
	$form->addGlobal(new Form_Input(
735
		'id',
736
		null,
737
		'hidden',
738
		$id
739
	));
740
}
741

    
742
$section = new Form_Section('Add a new certificate');
743

    
744
if (!isset($id))
745
{
746
	$section->addInput(new Form_Select(
747
		'method',
748
		'Method',
749
		$pconfig['method'],
750
		$cert_methods
751
	))->toggles();
752
}
753

    
754
$section->addInput(new Form_Input(
755
	'descr',
756
	'Descriptive name',
757
	'text',
758
	($a_user && empty($pconfig['descr'])) ? $a_user[$userid]['name'] : $pconfig['descr']
759
))->addClass('toggle-existing');
760

    
761
$form->add($section);
762
$section = new Form_Section('Import Certificate');
763
$section->addClass('toggle-import collapse');
764

    
765
$section->addInput(new Form_Textarea(
766
	'cert',
767
	'Certificate data',
768
	$pconfig['cert']
769
))->setHelp('Paste a certificate in X.509 PEM format here.');
770

    
771
$section->addInput(new Form_Textarea(
772
	'key',
773
	'Private key data',
774
	$pconfig['key']
775
))->setHelp('Paste a private key in X.509 PEM format here.');
776

    
777
$form->add($section);
778
$section = new Form_Section('Internal Certificate');
779
$section->addClass('toggle-internal collapse');
780

    
781
if (!$internal_ca_count)
782
{
783
	$section->addInput(new Form_StaticText(
784
		'Certificate authority',
785
		gettext('No internal Certificate Authorities have been defined. You must ').
786
		'<a href="system_camanager.php?act=new&amp;method=internal"> '. gettext(" create") .'</a>'.
787
		gettext(' an internal CA before creating an internal certificate.')
788
	));
789
}
790
else
791
{
792
	$allCas = array();
793
	foreach ($a_ca as $ca)
794
	{
795
		if (!$ca['prv'])
796
				continue;
797

    
798
		$allCas[ $ca['refid'] ] = $ca['descr'];
799
	}
800

    
801
	$section->addInput(new Form_Select(
802
		'caref',
803
		'Certificate authority',
804
		$pconfig['caref'],
805
		$allCas
806
	));
807
}
808

    
809
$section->addInput(new Form_Select(
810
	'keylen',
811
	'Key length',
812
	$pconfig['keylen'],
813
	array_combine($cert_keylens, $cert_keylens)
814
));
815

    
816
$section->addInput(new Form_Select(
817
	'digest_alg',
818
	'Digest Algorithm',
819
	$pconfig['digest_alg'],
820
	array_combine($openssl_digest_algs, $openssl_digest_algs)
821
))->setHelp('NOTE: It is recommended to use an algorithm stronger than '.
822
	'SHA1 when possible.');
823

    
824
$section->addInput(new Form_Select(
825
	'type',
826
	'Certificate Type',
827
	$pconfig['type'],
828
	$cert_types
829
))->setHelp('Type of certificate to generate. Used for placing '.
830
	'restrictions on the usage of the generated certificate.');
831

    
832
$section->addInput(new Form_Input(
833
	'lifetime',
834
	'Lifetime (days)',
835
	'number',
836
	$pconfig['lifetime']
837
));
838

    
839
$section->addInput(new Form_Select(
840
	'dn_country',
841
	'Country Code',
842
	$pconfig['dn_country'],
843
	$dn_cc
844
));
845

    
846
$section->addInput(new Form_Input(
847
	'dn_state',
848
	'State or Province',
849
	'text',
850
	$pconfig['dn_state'],
851
	['placeholder' => 'e.g. Texas']
852
));
853

    
854
$section->addInput(new Form_Input(
855
	'dn_city',
856
	'City',
857
	'text',
858
	$pconfig['dn_city'],
859
	['placeholder' => 'e.g. Austin']
860
));
861

    
862
$section->addInput(new Form_Input(
863
	'dn_organization',
864
	'Organization',
865
	'text',
866
	$pconfig['dn_organization'],
867
	['placeholder' => 'e.g. My Company Inc.']
868
));
869

    
870
$section->addInput(new Form_Input(
871
	'dn_email',
872
	'Email Address',
873
	'email',
874
	$pconfig['dn_email'],
875
	['placeholder' => 'e.g. admin@mycompany.com']
876
));
877

    
878
$section->addInput(new Form_Input(
879
	'dn_commonname',
880
	'Common Name',
881
	'text',
882
	$pconfig['dn_commonname'],
883
	['placeholder' => 'e.g. internal-ca']
884
));
885

    
886
$group = new Form_Group('Alternative Names');
887

    
888
if (empty($pconfig['altnames']['item']))
889
{
890
	$pconfig['altnames']['item'] = array(
891
		array('type' => null, 'value' => null)
892
	);
893
}
894

    
895
foreach ($pconfig['altnames']['item'] as $item)
896
{
897
	$group->add(new Form_Select(
898
		'altname_type',
899
		'Type',
900
		$item['type'],
901
		array(
902
			'DNS' => 'FQDN or Hostname',
903
			'IP' => 'IP address',
904
			'URI' => 'URI',
905
			'email' => 'email address',
906
		)
907
	));
908

    
909
	$group->add(new Form_Input(
910
		'altname_value',
911
		'Type',
912
		'text',
913
		$item['value']
914
	));
915

    
916
	$group->enableDuplication();
917
}
918

    
919
$section->add($group);
920

    
921
$form->add($section);
922
$section = new Form_Section('External Signing Request');
923
$section->addClass('toggle-external collapse');
924

    
925
$section->addInput(new Form_Select(
926
	'csr_keylen',
927
	'Key length',
928
	$pconfig['csr_keylen'],
929
	$cert_keylens
930
));
931

    
932
$section->addInput(new Form_Select(
933
	'csr_digest_alg',
934
	'Digest Algorithm',
935
	$pconfig['csr_digest_alg'],
936
	$openssl_digest_algs
937
))->setHelp('NOTE: It is recommended to use an algorithm stronger than '.
938
	'SHA1 when possible');
939

    
940
$section->addInput(new Form_Select(
941
	'dn_country',
942
	'Country Code',
943
	$pconfig['dn_country'],
944
	$dn_cc
945
));
946

    
947
$section->addInput(new Form_Input(
948
	'csr_dn_state',
949
	'State or Province',
950
	'text',
951
	$pconfig['csr_dn_state'],
952
	['placeholder' => 'e.g. Texas']
953
));
954

    
955
$section->addInput(new Form_Input(
956
	'csr_dn_city',
957
	'City',
958
	'text',
959
	$pconfig['csr_dn_city'],
960
	['placeholder' => 'e.g. Austin']
961
));
962

    
963
$section->addInput(new Form_Input(
964
	'csr_dn_organization',
965
	'Organization',
966
	'text',
967
	$pconfig['csr_dn_organization'],
968
	['placeholder' => 'e.g. My Company Inc.']
969
));
970

    
971
$section->addInput(new Form_Input(
972
	'csr_dn_email',
973
	'Email Address',
974
	'email',
975
	$pconfig['csr_dn_email'],
976
	['placeholder' => 'e.g. admin@mycompany.com']
977
));
978

    
979
$section->addInput(new Form_Input(
980
	'csr_dn_commonname',
981
	'Common Name',
982
	'text',
983
	$pconfig['csr_dn_commonname'],
984
	['placeholder' => 'e.g. internal-ca']
985
));
986

    
987
$form->add($section);
988
$section = new Form_Section('Choose an Existing Certificate');
989
$section->addClass('toggle-existing collapse');
990

    
991
$existCerts = array();
992

    
993
foreach ($config['cert'] as $cert)	{
994
	if(is_array($config['system']['user'][$userid]['cert'])) { // Could be MIA!
995
		if (isset($userid) && in_array($cert['refid'], $config['system']['user'][$userid]['cert']))
996
			continue;
997
	}
998

    
999
	$ca = lookup_ca($cert['caref']);
1000
	if ($ca)
1001
		$cert['descr'] .= " (CA: {$ca['descr']})";
1002

    
1003
	if (cert_in_use($cert['refid']))
1004
		$cert['descr'] .= " <i>In Use</i>";
1005
	if (is_cert_revoked($cert))
1006
		$cert['descr'] .= " <b>Revoked</b>";
1007

    
1008
	$existCerts[ $cert['refid'] ] = $cert['descr'];
1009
}
1010

    
1011

    
1012
$section->addInput(new Form_Select(
1013
	'certref',
1014
	'Existing Certificates',
1015
	$pconfig['certref'],
1016
	$existCerts
1017
));
1018

    
1019
$form->add($section);
1020
print $form;
1021

    
1022
?>
1023
<script>
1024
//<![CDATA[
1025
events.push(function(){
1026
<?php if ($internal_ca_count): ?>
1027
	function internalca_change() {
1028

    
1029
		caref = $('#caref').val();
1030

    
1031
		switch (caref) {
1032
<?php
1033
			foreach ($a_ca as $ca):
1034
				if (!$ca['prv']) {
1035
					continue;
1036
				}
1037

    
1038
				$subject = cert_get_subject_array($ca['crt']);
1039

    
1040
?>
1041
				case "<?=$ca['refid'];?>":
1042
					$('#dn_country').val("<?=$subject[0]['v'];?>");
1043
					$('#dn_state').val("<?=$subject[1]['v'];?>");
1044
					$('#dn_city').val("<?=$subject[2]['v'];?>");
1045
					$('#dn_organization').val("<?=$subject[3]['v'];?>");
1046
					$('#dn_email').val("<?=$subject[4]['v'];?>");
1047
					break;
1048
<?php
1049
			endforeach;
1050
?>
1051
		}
1052
	}
1053

    
1054
	// On click . .
1055
	$('#caref').on('change', function() {
1056
		internalca_change();
1057
	});
1058

    
1059
	// On page load . .
1060
	internalca_change();
1061

    
1062
<?php endif; ?>
1063

    
1064

    
1065
});
1066
//]]>
1067
</script>
1068
<?php
1069
include('foot.inc');
(196-196/238)