Project

General

Profile

Download (38.7 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * system_certmanager.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2018 Rubicon Communications, LLC (Netgate)
7
 * Copyright (c) 2008 Shrew Soft Inc
8
 * All rights reserved.
9
 *
10
 * Licensed under the Apache License, Version 2.0 (the "License");
11
 * you may not use this file except in compliance with the License.
12
 * You may obtain a copy of the License at
13
 *
14
 * http://www.apache.org/licenses/LICENSE-2.0
15
 *
16
 * Unless required by applicable law or agreed to in writing, software
17
 * distributed under the License is distributed on an "AS IS" BASIS,
18
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
 * See the License for the specific language governing permissions and
20
 * limitations under the License.
21
 */
22

    
23
##|+PRIV
24
##|*IDENT=page-system-certmanager
25
##|*NAME=System: Certificate Manager
26
##|*DESCR=Allow access to the 'System: Certificate Manager' page.
27
##|*MATCH=system_certmanager.php*
28
##|-PRIV
29

    
30
require_once("guiconfig.inc");
31
require_once("certs.inc");
32
require_once("pfsense-utils.inc");
33

    
34
$cert_methods = array(
35
	"internal" => gettext("Create an internal Certificate"),
36
	"import" => gettext("Import an existing Certificate"),
37
	"external" => gettext("Create a Certificate Signing Request"),
38
	"sign" => gettext("Sign a Certificate Signing Request")
39
);
40

    
41
$cert_keylens = array("1024", "2048", "3072", "4096", "6144", "7680", "8192", "15360", "16384");
42
$cert_types = array(
43
	"server" => "Server Certificate",
44
	"user" => "User Certificate");
45

    
46
global $cert_altname_types;
47
global $openssl_digest_algs;
48

    
49
if (isset($_REQUEST['userid']) && is_numericint($_REQUEST['userid'])) {
50
	$userid = $_REQUEST['userid'];
51
}
52

    
53
if (isset($userid)) {
54
	$cert_methods["existing"] = gettext("Choose an existing certificate");
55
	if (!is_array($config['system']['user'])) {
56
		$config['system']['user'] = array();
57
	}
58
	$a_user =& $config['system']['user'];
59
}
60

    
61
if (isset($_REQUEST['id']) && is_numericint($_REQUEST['id'])) {
62
	$id = $_REQUEST['id'];
63
}
64

    
65
if (!is_array($config['ca'])) {
66
	$config['ca'] = array();
67
}
68

    
69
$a_ca =& $config['ca'];
70

    
71
if (!is_array($config['cert'])) {
72
	$config['cert'] = array();
73
}
74

    
75
$a_cert =& $config['cert'];
76

    
77
$internal_ca_count = 0;
78
foreach ($a_ca as $ca) {
79
	if ($ca['prv']) {
80
		$internal_ca_count++;
81
	}
82
}
83

    
84
$act = $_REQUEST['act'];
85

    
86
if ($_POST['act'] == "del") {
87

    
88
	if (!isset($a_cert[$id])) {
89
		pfSenseHeader("system_certmanager.php");
90
		exit;
91
	}
92

    
93
	unset($a_cert[$id]);
94
	write_config();
95
	$savemsg = sprintf(gettext("Certificate %s successfully deleted."), htmlspecialchars($a_cert[$id]['descr']));
96
	pfSenseHeader("system_certmanager.php");
97
	exit;
98
}
99

    
100
if ($act == "new") {
101
	$pconfig['method'] = $_POST['method'];
102
	$pconfig['keylen'] = "2048";
103
	$pconfig['digest_alg'] = "sha256";
104
	$pconfig['csr_keylen'] = "2048";
105
	$pconfig['csr_digest_alg'] = "sha256";
106
	$pconfig['csrsign_digest_alg'] = "sha256";
107
	$pconfig['type'] = "user";
108
	$pconfig['lifetime'] = "3650";
109
}
110

    
111
if ($act == "exp") {
112

    
113
	if (!$a_cert[$id]) {
114
		pfSenseHeader("system_certmanager.php");
115
		exit;
116
	}
117

    
118
	$exp_name = urlencode("{$a_cert[$id]['descr']}.crt");
119
	$exp_data = base64_decode($a_cert[$id]['crt']);
120
	$exp_size = strlen($exp_data);
121

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

    
129
if ($act == "req") {
130

    
131
	if (!$a_cert[$id]) {
132
		pfSenseHeader("system_certmanager.php");
133
		exit;
134
	}
135

    
136
	$exp_name = urlencode("{$a_cert[$id]['descr']}.req");
137
	$exp_data = base64_decode($a_cert[$id]['csr']);
138
	$exp_size = strlen($exp_data);
139

    
140
	header("Content-Type: application/octet-stream");
141
	header("Content-Disposition: attachment; filename={$exp_name}");
142
	header("Content-Length: $exp_size");
143
	echo $exp_data;
144
	exit;
145
}
146

    
147
if ($act == "key") {
148

    
149
	if (!$a_cert[$id]) {
150
		pfSenseHeader("system_certmanager.php");
151
		exit;
152
	}
153

    
154
	$exp_name = urlencode("{$a_cert[$id]['descr']}.key");
155
	$exp_data = base64_decode($a_cert[$id]['prv']);
156
	$exp_size = strlen($exp_data);
157

    
158
	header("Content-Type: application/octet-stream");
159
	header("Content-Disposition: attachment; filename={$exp_name}");
160
	header("Content-Length: $exp_size");
161
	echo $exp_data;
162
	exit;
163
}
164

    
165
if ($act == "p12") {
166
	if (!$a_cert[$id]) {
167
		pfSenseHeader("system_certmanager.php");
168
		exit;
169
	}
170

    
171
	$exp_name = urlencode("{$a_cert[$id]['descr']}.p12");
172
	$args = array();
173
	$args['friendly_name'] = $a_cert[$id]['descr'];
174

    
175
	$ca = lookup_ca($a_cert[$id]['caref']);
176

    
177
	if ($ca) {
178
		$args['extracerts'] = openssl_x509_read(base64_decode($ca['crt']));
179
	}
180

    
181
	$res_crt = openssl_x509_read(base64_decode($a_cert[$id]['crt']));
182
	$res_key = openssl_pkey_get_private(array(0 => base64_decode($a_cert[$id]['prv']) , 1 => ""));
183

    
184
	$exp_data = "";
185
	openssl_pkcs12_export($res_crt, $exp_data, $res_key, null, $args);
186
	$exp_size = strlen($exp_data);
187

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

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

    
201
	$pconfig['descr'] = $a_cert[$id]['descr'];
202
	$pconfig['csr'] = base64_decode($a_cert[$id]['csr']);
203
}
204

    
205
if ($_POST['save']) {
206

    
207
	if ($_POST['save'] == gettext("Save")) {
208
		$input_errors = array();
209
		$pconfig = $_POST;
210

    
211
		/* input validation */
212
		if ($pconfig['method'] == "sign") {
213
			$reqdfields = explode(" ",
214
				"descr catosignwith");
215
			$reqdfieldsn = array(
216
				gettext("Descriptive name"),
217
				gettext("CA to sign with"));
218

    
219
			if (($_POST['csrtosign'] === "new") &&
220
			    ((!strstr($_POST['csrpaste'], "BEGIN CERTIFICATE REQUEST") || !strstr($_POST['csrpaste'], "END CERTIFICATE REQUEST")) &&
221
			    (!strstr($_POST['csrpaste'], "BEGIN NEW CERTIFICATE REQUEST") || !strstr($_POST['csrpaste'], "END NEW CERTIFICATE REQUEST")))) {
222
				$input_errors[] = gettext("This signing request does not appear to be valid.");
223
			}
224

    
225
			if ( (($_POST['csrtosign'] === "new") && (strlen($_POST['keypaste']) > 0)) && (!strstr($_POST['keypaste'], "BEGIN PRIVATE KEY") || !strstr($_POST['keypaste'], "END PRIVATE KEY"))) {
226
				$input_errors[] = gettext("This private does not appear to be valid.");
227
				$input_errors[] = gettext("Key data field should be blank, or a valid x509 private key");
228
			}
229

    
230
		}
231

    
232
		if ($pconfig['method'] == "import") {
233
			$reqdfields = explode(" ",
234
				"descr cert key");
235
			$reqdfieldsn = array(
236
				gettext("Descriptive name"),
237
				gettext("Certificate data"),
238
				gettext("Key data"));
239
			if ($_POST['cert'] && (!strstr($_POST['cert'], "BEGIN CERTIFICATE") || !strstr($_POST['cert'], "END CERTIFICATE"))) {
240
				$input_errors[] = gettext("This certificate does not appear to be valid.");
241
			}
242

    
243
			if (cert_get_publickey($_POST['cert'], false) != cert_get_publickey($_POST['key'], false, 'prv')) {
244
				$input_errors[] = gettext("The submitted private key does not match the submitted certificate data.");
245
			}
246
		}
247

    
248
		if ($pconfig['method'] == "internal") {
249
			$reqdfields = explode(" ",
250
				"descr caref keylen type lifetime dn_commonname");
251
			$reqdfieldsn = array(
252
				gettext("Descriptive name"),
253
				gettext("Certificate authority"),
254
				gettext("Key length"),
255
				gettext("Certificate Type"),
256
				gettext("Lifetime"),
257
				gettext("Distinguished name Common Name"));
258
		}
259

    
260
		if ($pconfig['method'] == "external") {
261
			$reqdfields = explode(" ",
262
				"descr csr_keylen csr_dn_commonname");
263
			$reqdfieldsn = array(
264
				gettext("Descriptive name"),
265
				gettext("Key length"),
266
				gettext("Distinguished name Common Name"));
267
		}
268

    
269
		if ($pconfig['method'] == "existing") {
270
			$reqdfields = array("certref");
271
			$reqdfieldsn = array(gettext("Existing Certificate Choice"));
272
		}
273

    
274
		$altnames = array();
275
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
276

    
277
		if ($pconfig['method'] != "import" && $pconfig['method'] != "existing") {
278
			/* subjectAltNames */
279
			$san_typevar = 'altname_type';
280
			$san_valuevar = 'altname_value';
281
			// This is just the blank alternate name that is added for display purposes. We don't want to validate/save it
282
			if ($_POST["{$san_valuevar}0"] == "") {
283
				unset($_POST["{$san_typevar}0"]);
284
				unset($_POST["{$san_valuevar}0"]);
285
			}
286
			foreach ($_POST as $key => $value) {
287
				$entry = '';
288
				if (!substr_compare($san_typevar, $key, 0, strlen($san_typevar))) {
289
					$entry = substr($key, strlen($san_typevar));
290
					$field = 'type';
291
				} elseif (!substr_compare($san_valuevar, $key, 0, strlen($san_valuevar))) {
292
					$entry = substr($key, strlen($san_valuevar));
293
					$field = 'value';
294
				}
295

    
296
				if (ctype_digit($entry)) {
297
					$entry++;	// Pre-bootstrap code is one-indexed, but the bootstrap code is 0-indexed
298
					$altnames[$entry][$field] = $value;
299
				}
300
			}
301

    
302
			$pconfig['altnames']['item'] = $altnames;
303

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

    
336
			/* Make sure we do not have invalid characters in the fields for the certificate */
337

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

    
342
			if (($pconfig['method'] != "external") && isset($_POST["keylen"]) && !in_array($_POST["keylen"], $cert_keylens)) {
343
				array_push($input_errors, gettext("Please select a valid Key Length."));
344
			}
345
			if (($pconfig['method'] != "external") && !in_array($_POST["digest_alg"], $openssl_digest_algs)) {
346
				array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
347
			}
348

    
349
			if (($pconfig['method'] == "external") && isset($_POST["csr_keylen"]) && !in_array($_POST["csr_keylen"], $cert_keylens)) {
350
				array_push($input_errors, gettext("Please select a valid Key Length."));
351
			}
352
			if (($pconfig['method'] == "external") && !in_array($_POST["csr_digest_alg"], $openssl_digest_algs)) {
353
				array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
354
			}
355
			if (($pconfig['method'] == "sign") && !in_array($_POST["csrsign_digest_alg"], $openssl_digest_algs)) {
356
				array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
357
			}
358
		}
359

    
360
		/* save modifications */
361
		if (!$input_errors) {
362

    
363
			if ($pconfig['method'] == "existing") {
364
				$cert = lookup_cert($pconfig['certref']);
365
				if ($cert && $a_user) {
366
					$a_user[$userid]['cert'][] = $cert['refid'];
367
				}
368
			} else if ($pconfig['method'] == "sign") { // Sign a CSR
369
				$csrid = lookup_cert($pconfig['csrtosign']);
370
				$ca = & lookup_ca($pconfig['catosignwith']);
371

    
372
				// Read the CSR from $config, or if a new one, from the textarea
373
				if ($pconfig['csrtosign'] === "new") {
374
					$csr = $pconfig['csrpaste'];
375
				} else {
376
					$csr = base64_decode($csrid['csr']);
377
				}
378
				if (count($altnames)) {
379
					foreach ($altnames as $altname) {
380
						$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
381
					}
382
					$altname_str = implode(",", $altnames_tmp);
383
				}
384

    
385
				$n509 = csr_sign($csr, $ca, $pconfig['csrsign_lifetime'], $pconfig['type'], $altname_str, $pconfig['csrsign_digest_alg']);
386

    
387
				if ($n509) {
388
					// Gather the details required to save the new cert
389
					$newcert = array();
390
					$newcert['refid'] = uniqid();
391
					$newcert['caref'] = $pconfig['catosignwith'];
392
					$newcert['descr'] = $pconfig['descr'];
393
					$newcert['type'] = $pconfig['type'];
394
					$newcert['crt'] = base64_encode($n509);
395

    
396
					if ($pconfig['csrtosign'] === "new") {
397
						$newcert['prv'] = base64_encode($pconfig['keypaste']);
398
					} else {
399
						$newcert['prv'] = $csrid['prv'];
400
					}
401

    
402
					// Add it to the config file
403
					$config['cert'][] = $newcert;
404
				}
405

    
406
			} else {
407
				$cert = array();
408
				$cert['refid'] = uniqid();
409
				if (isset($id) && $a_cert[$id]) {
410
					$cert = $a_cert[$id];
411
				}
412

    
413
				$cert['descr'] = $pconfig['descr'];
414

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

    
417
				if ($pconfig['method'] == "import") {
418
					cert_import($cert, $pconfig['cert'], $pconfig['key']);
419
				}
420

    
421
				if ($pconfig['method'] == "internal") {
422
					$dn = array('commonName' => cert_escape_x509_chars($pconfig['dn_commonname']));
423
					if (!empty($pconfig['dn_country'])) {
424
						$dn['countryName'] = $pconfig['dn_country'];
425
					}
426
					if (!empty($pconfig['dn_state'])) {
427
						$dn['stateOrProvinceName'] = cert_escape_x509_chars($pconfig['dn_state']);
428
					}
429
					if (!empty($pconfig['dn_city'])) {
430
						$dn['localityName'] = cert_escape_x509_chars($pconfig['dn_city']);
431
					}
432
					if (!empty($pconfig['dn_organization'])) {
433
						$dn['organizationName'] = cert_escape_x509_chars($pconfig['dn_organization']);
434
					}
435
					if (!empty($pconfig['dn_organizationalunit'])) {
436
						$dn['organizationalUnitName'] = cert_escape_x509_chars($pconfig['dn_organizationalunit']);
437
					}
438

    
439
					$altnames_tmp = array();
440
					$cn_altname = cert_add_altname_type($pconfig['dn_commonname']);
441
					if (!empty($cn_altname)) {
442
						$altnames_tmp[] = $cn_altname;
443
					}
444
					if (count($altnames)) {
445
						foreach ($altnames as $altname) {
446
							// The CN is added as a SAN automatically, do not add it again.
447
							if ($altname['value'] != $pconfig['dn_commonname']) {
448
								$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
449
							}
450
						}
451
					}
452
					if (!empty($altnames_tmp)) {
453
						$dn['subjectAltName'] = implode(",", $altnames_tmp);
454
					}
455

    
456
					if (!cert_create($cert, $pconfig['caref'], $pconfig['keylen'], $pconfig['lifetime'], $dn, $pconfig['type'], $pconfig['digest_alg'])) {
457
						$input_errors = array();
458
						while ($ssl_err = openssl_error_string()) {
459
							if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
460
								array_push($input_errors, "openssl library returns: " . $ssl_err);
461
							}
462
						}
463
					}
464
				}
465

    
466
				if ($pconfig['method'] == "external") {
467
					$dn = array('commonName' => cert_escape_x509_chars($pconfig['csr_dn_commonname']));
468
					if (!empty($pconfig['csr_dn_country'])) {
469
						$dn['countryName'] = $pconfig['csr_dn_country'];
470
					}
471
					if (!empty($pconfig['csr_dn_state'])) {
472
						$dn['stateOrProvinceName'] = cert_escape_x509_chars($pconfig['csr_dn_state']);
473
					}
474
					if (!empty($pconfig['csr_dn_city'])) {
475
						$dn['localityName'] = cert_escape_x509_chars($pconfig['csr_dn_city']);
476
					}
477
					if (!empty($pconfig['csr_dn_organization'])) {
478
						$dn['organizationName'] = cert_escape_x509_chars($pconfig['csr_dn_organization']);
479
					}
480
					if (!empty($pconfig['csr_dn_organizationalunit'])) {
481
						$dn['organizationalUnitName'] = cert_escape_x509_chars($pconfig['csr_dn_organizationalunit']);
482
					}
483

    
484
					$altnames_tmp = array();
485
					$cn_altname = cert_add_altname_type($pconfig['csr_dn_commonname']);
486
					if (!empty($cn_altname)) {
487
						$altnames_tmp[] = $cn_altname;
488
					}
489
					if (count($altnames)) {
490
						foreach ($altnames as $altname) {
491
							// The CN is added as a SAN automatically, do not add it again.
492
							if ($altname['value'] != $pconfig['csr_dn_commonname']) {
493
								$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
494
							}
495
						}
496
					}
497
					if (!empty($altnames_tmp)) {
498
						$dn['subjectAltName'] = implode(",", $altnames_tmp);
499
					}
500

    
501
					if (!csr_generate($cert, $pconfig['csr_keylen'], $dn, $pconfig['type'], $pconfig['csr_digest_alg'])) {
502
						$input_errors = array();
503
						while ($ssl_err = openssl_error_string()) {
504
							if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
505
								array_push($input_errors, "openssl library returns: " . $ssl_err);
506
							}
507
						}
508
					}
509
				}
510

    
511
				error_reporting($old_err_level);
512

    
513
				if (isset($id) && $a_cert[$id]) {
514
					$a_cert[$id] = $cert;
515
				} else {
516
					$a_cert[] = $cert;
517
				}
518

    
519
				if (isset($a_user) && isset($userid)) {
520
					$a_user[$userid]['cert'][] = $cert['refid'];
521
				}
522
			}
523

    
524
			if (!$input_errors) {
525
				write_config();
526
			}
527

    
528
			if ((isset($userid) && is_numeric($userid)) && !$input_errors) {
529
				post_redirect("system_usermanager.php", array('act' => 'edit', 'userid' => $userid));
530
				exit;
531
			}
532
		}
533
	}
534

    
535
	if ($_POST['save'] == gettext("Update")) {
536
		unset($input_errors);
537
		$pconfig = $_POST;
538

    
539
		/* input validation */
540
		$reqdfields = explode(" ", "descr cert");
541
		$reqdfieldsn = array(
542
			gettext("Descriptive name"),
543
			gettext("Final Certificate data"));
544

    
545
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
546

    
547
		if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
548
			array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
549
		}
550

    
551
//		old way
552
		/* make sure this csr and certificate subjects match */
553
//		$subj_csr = csr_get_subject($pconfig['csr'], false);
554
//		$subj_cert = cert_get_subject($pconfig['cert'], false);
555
//
556
//		if (!isset($_POST['ignoresubjectmismatch']) && !($_POST['ignoresubjectmismatch'] == "yes")) {
557
//			if (strcmp($subj_csr, $subj_cert)) {
558
//				$input_errors[] = sprintf(gettext("The certificate subject '%s' does not match the signing request subject."), $subj_cert);
559
//				$subject_mismatch = true;
560
//			}
561
//		}
562
		$mod_csr = cert_get_publickey($pconfig['csr'], false, 'csr');
563
		$mod_cert = cert_get_publickey($pconfig['cert'], false);
564

    
565
		if (strcmp($mod_csr, $mod_cert)) {
566
			// simply: if the moduli don't match, then the private key and public key won't match
567
			$input_errors[] = sprintf(gettext("The certificate public key does not match the signing request public key."), $subj_cert);
568
			$subject_mismatch = true;
569
		}
570

    
571
		/* save modifications */
572
		if (!$input_errors) {
573

    
574
			$cert = $a_cert[$id];
575

    
576
			$cert['descr'] = $pconfig['descr'];
577

    
578
			csr_complete($cert, $pconfig['cert']);
579

    
580
			$a_cert[$id] = $cert;
581

    
582
			write_config();
583

    
584
			pfSenseHeader("system_certmanager.php");
585
		}
586
	}
587
}
588

    
589
$pgtitle = array(gettext("System"), gettext("Certificate Manager"), gettext("Certificates"));
590
$pglinks = array("", "system_camanager.php", "system_certmanager.php");
591

    
592
if (($act == "new" || ($_POST['save'] == gettext("Save") && $input_errors)) || ($act == "csr" || ($_POST['save'] == gettext("Update") && $input_errors))) {
593
	$pgtitle[] = gettext('Edit');
594
	$pglinks[] = "@self";
595
}
596
include("head.inc");
597

    
598
if ($input_errors) {
599
	print_input_errors($input_errors);
600
}
601

    
602
if ($savemsg) {
603
	print_info_box($savemsg, 'success');
604
}
605

    
606
$tab_array = array();
607
$tab_array[] = array(gettext("CAs"), false, "system_camanager.php");
608
$tab_array[] = array(gettext("Certificates"), true, "system_certmanager.php");
609
$tab_array[] = array(gettext("Certificate Revocation"), false, "system_crlmanager.php");
610
display_top_tabs($tab_array);
611

    
612
// Load valid country codes
613
$dn_cc = array();
614
if (file_exists("/etc/ca_countries")) {
615
	$dn_cc_file=file("/etc/ca_countries");
616
	$dn_cc[''] = gettext("None");
617
	foreach ($dn_cc_file as $line) {
618
		if (preg_match('/^(\S*)\s(.*)$/', $line, $matches)) {
619
			$dn_cc[$matches[1]] = $matches[1];
620
		}
621
	}
622
}
623

    
624
if ($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)) {
625
	$form = new Form();
626
	$form->setAction('system_certmanager.php?act=edit');
627

    
628
	if (isset($userid) && $a_user) {
629
		$form->addGlobal(new Form_Input(
630
			'userid',
631
			null,
632
			'hidden',
633
			$userid
634
		));
635
	}
636

    
637
	if (isset($id) && $a_cert[$id]) {
638
		$form->addGlobal(new Form_Input(
639
			'id',
640
			null,
641
			'hidden',
642
			$id
643
		));
644
	}
645

    
646
	$section = new Form_Section('Add/Sign a New Certificate');
647

    
648
	if (!isset($id)) {
649
		$section->addInput(new Form_Select(
650
			'method',
651
			'*Method',
652
			$pconfig['method'],
653
			$cert_methods
654
		))->toggles();
655
	}
656

    
657
	$section->addInput(new Form_Input(
658
		'descr',
659
		'*Descriptive name',
660
		'text',
661
		($a_user && empty($pconfig['descr'])) ? $a_user[$userid]['name'] : $pconfig['descr']
662
	))->addClass('toggle-existing');
663

    
664
	$form->add($section);
665

    
666
	// Return an array containing the IDs od all CAs
667
	function list_cas() {
668
		global $a_ca;
669
		$allCas = array();
670

    
671
		foreach ($a_ca as $ca) {
672
			if ($ca['prv']) {
673
				$allCas[$ca['refid']] = $ca['descr'];
674
			}
675
		}
676

    
677
		return $allCas;
678
	}
679

    
680
	// Return an array containing the IDs od all CSRs
681
	function list_csrs() {
682
		global $config;
683
		$allCsrs = array();
684

    
685
		foreach ($config['cert'] as $cert) {
686
			if ($cert['csr']) {
687
				$allCsrs[$cert['refid']] = $cert['descr'];
688
			}
689
		}
690

    
691
		return ['new' => gettext('New CSR (Paste below)')] + $allCsrs;
692
	}
693

    
694
	$section = new Form_Section('Sign CSR');
695
	$section->addClass('toggle-sign collapse');
696

    
697
	$section->AddInput(new Form_Select(
698
		'catosignwith',
699
		'*CA to sign with',
700
		$pconfig['catosignwith'],
701
		list_cas()
702
	));
703

    
704
	$section->AddInput(new Form_Select(
705
		'csrtosign',
706
		'*CSR to sign',
707
		isset($pconfig['csrtosign']) ? $pconfig['csrtosign'] : 'new',
708
		list_csrs()
709
	));
710

    
711
	$section->addInput(new Form_Textarea(
712
		'csrpaste',
713
		'CSR data',
714
		$pconfig['csrpaste']
715
	))->setHelp('Paste a Certificate Signing Request in X.509 PEM format here.');
716

    
717
	$section->addInput(new Form_Textarea(
718
		'keypaste',
719
		'Key data',
720
		$pconfig['keypaste']
721
	))->setHelp('Optionally paste a private key here. The key will be associated with the newly signed certificate in pfSense');
722

    
723
	$section->addInput(new Form_Input(
724
		'csrsign_lifetime',
725
		'*Certificate Lifetime (days)',
726
		'number',
727
		$pconfig['csrsign_lifetime'] ? $pconfig['csrsign_lifetime']:'3650'
728
	));
729
	$section->addInput(new Form_Select(
730
		'csrsign_digest_alg',
731
		'*Digest Algorithm',
732
		$pconfig['csrsign_digest_alg'],
733
		array_combine($openssl_digest_algs, $openssl_digest_algs)
734
	))->setHelp('NOTE: It is recommended to use an algorithm stronger than '.
735
		'SHA1 when possible');
736

    
737
	$form->add($section);
738

    
739
	$section = new Form_Section('Import Certificate');
740
	$section->addClass('toggle-import collapse');
741

    
742
	$section->addInput(new Form_Textarea(
743
		'cert',
744
		'*Certificate data',
745
		$pconfig['cert']
746
	))->setHelp('Paste a certificate in X.509 PEM format here.');
747

    
748
	$section->addInput(new Form_Textarea(
749
		'key',
750
		'*Private key data',
751
		$pconfig['key']
752
	))->setHelp('Paste a private key in X.509 PEM format here.');
753

    
754
	$form->add($section);
755
	$section = new Form_Section('Internal Certificate');
756
	$section->addClass('toggle-internal collapse');
757

    
758
	if (!$internal_ca_count) {
759
		$section->addInput(new Form_StaticText(
760
			'*Certificate authority',
761
			gettext('No internal Certificate Authorities have been defined. ') .
762
			gettext('An internal CA must be defined in order to create an internal certificate. ') .
763
			sprintf(gettext('%1$sCreate%2$s an internal CA.'), '<a href="system_camanager.php?act=new&amp;method=internal"> ', '</a>')
764
		));
765
	} else {
766
		$allCas = array();
767
		foreach ($a_ca as $ca) {
768
			if (!$ca['prv']) {
769
				continue;
770
			}
771

    
772
			$allCas[ $ca['refid'] ] = $ca['descr'];
773
		}
774

    
775
		$section->addInput(new Form_Select(
776
			'caref',
777
			'*Certificate authority',
778
			$pconfig['caref'],
779
			$allCas
780
		));
781
	}
782

    
783
	$section->addInput(new Form_Select(
784
		'keylen',
785
		'*Key length',
786
		$pconfig['keylen'],
787
		array_combine($cert_keylens, $cert_keylens)
788
	));
789

    
790
	$section->addInput(new Form_Select(
791
		'digest_alg',
792
		'*Digest Algorithm',
793
		$pconfig['digest_alg'],
794
		array_combine($openssl_digest_algs, $openssl_digest_algs)
795
	))->setHelp('NOTE: It is recommended to use an algorithm stronger than '.
796
		'SHA1 when possible.');
797

    
798
	$section->addInput(new Form_Input(
799
		'lifetime',
800
		'*Lifetime (days)',
801
		'number',
802
		$pconfig['lifetime']
803
	));
804

    
805
	$section->addInput(new Form_Input(
806
		'dn_commonname',
807
		'*Common Name',
808
		'text',
809
		$pconfig['dn_commonname'],
810
		['placeholder' => 'e.g. www.example.com']
811
	));
812

    
813
	$section->addInput(new Form_StaticText(
814
		null,
815
		gettext('The following certificate subject components are optional and may be left blank.')
816
	));
817

    
818
	$section->addInput(new Form_Select(
819
		'dn_country',
820
		'Country Code',
821
		$pconfig['dn_country'],
822
		$dn_cc
823
	));
824

    
825
	$section->addInput(new Form_Input(
826
		'dn_state',
827
		'State or Province',
828
		'text',
829
		$pconfig['dn_state'],
830
		['placeholder' => 'e.g. Texas']
831
	));
832

    
833
	$section->addInput(new Form_Input(
834
		'dn_city',
835
		'City',
836
		'text',
837
		$pconfig['dn_city'],
838
		['placeholder' => 'e.g. Austin']
839
	));
840

    
841
	$section->addInput(new Form_Input(
842
		'dn_organization',
843
		'Organization',
844
		'text',
845
		$pconfig['dn_organization'],
846
		['placeholder' => 'e.g. My Company Inc']
847
	));
848

    
849
	$section->addInput(new Form_Input(
850
		'dn_organizationalunit',
851
		'Organizational Unit',
852
		'text',
853
		$pconfig['dn_organizationalunit'],
854
		['placeholder' => 'e.g. My Department Name (optional)']
855
	));
856

    
857
	$form->add($section);
858
	$section = new Form_Section('External Signing Request');
859
	$section->addClass('toggle-external collapse');
860

    
861
	$section->addInput(new Form_Select(
862
		'csr_keylen',
863
		'*Key length',
864
		$pconfig['csr_keylen'],
865
		array_combine($cert_keylens, $cert_keylens)
866
	));
867

    
868
	$section->addInput(new Form_Select(
869
		'csr_digest_alg',
870
		'*Digest Algorithm',
871
		$pconfig['csr_digest_alg'],
872
		array_combine($openssl_digest_algs, $openssl_digest_algs)
873
	))->setHelp('NOTE: It is recommended to use an algorithm stronger than '.
874
		'SHA1 when possible');
875

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

    
884
	$section->addInput(new Form_StaticText(
885
		null,
886
		gettext('The following certificate subject components are optional and may be left blank.')
887
	));
888

    
889
	$section->addInput(new Form_Select(
890
		'csr_dn_country',
891
		'Country Code',
892
		$pconfig['csr_dn_country'],
893
		$dn_cc
894
	));
895

    
896
	$section->addInput(new Form_Input(
897
		'csr_dn_state',
898
		'State or Province',
899
		'text',
900
		$pconfig['csr_dn_state'],
901
		['placeholder' => 'e.g. Texas']
902
	));
903

    
904
	$section->addInput(new Form_Input(
905
		'csr_dn_city',
906
		'City',
907
		'text',
908
		$pconfig['csr_dn_city'],
909
		['placeholder' => 'e.g. Austin']
910
	));
911

    
912
	$section->addInput(new Form_Input(
913
		'csr_dn_organization',
914
		'Organization',
915
		'text',
916
		$pconfig['csr_dn_organization'],
917
		['placeholder' => 'e.g. My Company Inc']
918
	));
919

    
920
	$section->addInput(new Form_Input(
921
		'csr_dn_organizationalunit',
922
		'Organizational Unit',
923
		'text',
924
		$pconfig['csr_dn_organizationalunit'],
925
		['placeholder' => 'e.g. My Department Name (optional)']
926
	));
927

    
928
	$form->add($section);
929
	$section = new Form_Section('Choose an Existing Certificate');
930
	$section->addClass('toggle-existing collapse');
931

    
932
	$existCerts = array();
933

    
934
	foreach ($config['cert'] as $cert)	{
935
		if (is_array($config['system']['user'][$userid]['cert'])) { // Could be MIA!
936
			if (isset($userid) && in_array($cert['refid'], $config['system']['user'][$userid]['cert'])) {
937
				continue;
938
			}
939
		}
940

    
941
		$ca = lookup_ca($cert['caref']);
942
		if ($ca) {
943
			$cert['descr'] .= " (CA: {$ca['descr']})";
944
		}
945

    
946
		if (cert_in_use($cert['refid'])) {
947
			$cert['descr'] .= " (In Use)";
948
		}
949
		if (is_cert_revoked($cert)) {
950
			$cert['descr'] .= " (Revoked)";
951
		}
952

    
953
		$existCerts[ $cert['refid'] ] = $cert['descr'];
954
	}
955

    
956
	$section->addInput(new Form_Select(
957
		'certref',
958
		'*Existing Certificates',
959
		$pconfig['certref'],
960
		$existCerts
961
	));
962

    
963
	$form->add($section);
964

    
965
	$section = new Form_Section('Certificate Attributes');
966
	$section->addClass('toggle-external toggle-internal toggle-sign collapse');
967

    
968
	$section->addInput(new Form_StaticText(
969
		gettext('Attribute Notes'),
970
		'<span class="help-block">'.
971
		gettext('The following attributes are added to certificates and ' .
972
		'requests when they are created or signed. These attributes behave ' .
973
		'differently depending on the selected mode.') .
974
		'<br/><br/>' .
975
		'<span class="toggle-internal collapse">' . gettext('For Internal Certificates, these attributes are added directly to the certificate as shown.') . '</span>' .
976
		'<span class="toggle-external collapse">' .
977
		gettext('For Certificate Signing Requests, These attributes are added to the request but they may be ignored or changed by the CA that signs the request. ') .
978
		'<br/><br/>' .
979
		gettext('If this CSR will be signed using the Certificate Manager on this firewall, set the attributes when signing instead as they cannot be carried over.') . '</span>' .
980
		'<span class="toggle-sign collapse">' . gettext('When Signing a Certificate Request, existing attributes in the request cannot be copied. The attributes below will be applied to the resulting certificate.') . '</span>' .
981
		'</span>'
982
	));
983

    
984
	$section->addInput(new Form_Select(
985
		'type',
986
		'*Certificate Type',
987
		$pconfig['type'],
988
		$cert_types
989
	))->setHelp('Add type-specific usage attributes to the signed certificate.' .
990
		' Used for placing usage restrictions on, or granting abilities to, ' .
991
		'the signed certificate.');
992

    
993
	if (empty($pconfig['altnames']['item'])) {
994
		$pconfig['altnames']['item'] = array(
995
			array('type' => null, 'value' => null)
996
		);
997
	}
998

    
999
	$counter = 0;
1000
	$numrows = count($pconfig['altnames']['item']) - 1;
1001

    
1002
	foreach ($pconfig['altnames']['item'] as $item) {
1003

    
1004
		$group = new Form_Group($counter == 0 ? 'Alternative Names':'');
1005

    
1006
		$group->add(new Form_Select(
1007
			'altname_type' . $counter,
1008
			'Type',
1009
			$item['type'],
1010
			$cert_altname_types
1011
		))->setHelp(($counter == $numrows) ? 'Type':null);
1012

    
1013
		$group->add(new Form_Input(
1014
			'altname_value' . $counter,
1015
			null,
1016
			'text',
1017
			$item['value']
1018
		))->setHelp(($counter == $numrows) ? 'Value':null);
1019

    
1020
		$group->add(new Form_Button(
1021
			'deleterow' . $counter,
1022
			'Delete',
1023
			null,
1024
			'fa-trash'
1025
		))->addClass('btn-warning');
1026

    
1027
		$group->addClass('repeatable');
1028

    
1029
		$group->setHelp('Enter additional identifiers for the certificate ' .
1030
			'in this list. The Common Name field is automatically ' .
1031
			'added to the certificate as an Alternative Name. ' .
1032
			'The signing CA may ignore or change these values.');
1033

    
1034
		$section->add($group);
1035

    
1036
		$counter++;
1037
	}
1038

    
1039
	$section->addInput(new Form_Button(
1040
		'addrow',
1041
		'Add',
1042
		null,
1043
		'fa-plus'
1044
	))->addClass('btn-success');
1045

    
1046
	$form->add($section);
1047

    
1048

    
1049
	print $form;
1050

    
1051
} else if ($act == "csr" || (($_POST['save'] == gettext("Update")) && $input_errors)) {
1052
	$form = new Form(false);
1053
	$form->setAction('system_certmanager.php?act=csr');
1054

    
1055
	$section = new Form_Section("Complete Signing Request for " . $pconfig['descr']);
1056

    
1057
	$section->addInput(new Form_Input(
1058
		'descr',
1059
		'*Descriptive name',
1060
		'text',
1061
		$pconfig['descr']
1062
	));
1063

    
1064
	$section->addInput(new Form_Textarea(
1065
		'csr',
1066
		'Signing request data',
1067
		$pconfig['csr']
1068
	))->setReadonly()
1069
	  ->setWidth(7)
1070
	  ->setHelp('Copy the certificate signing data from here and forward it to a certificate authority for signing.');
1071

    
1072
	$section->addInput(new Form_Textarea(
1073
		'cert',
1074
		'*Final certificate data',
1075
		$pconfig['cert']
1076
	))->setWidth(7)
1077
	  ->setHelp('Paste the certificate received from the certificate authority here.');
1078

    
1079
	 if (isset($id) && $a_cert[$id]) {
1080
		 $section->addInput(new Form_Input(
1081
			'id',
1082
			null,
1083
			'hidden',
1084
			$id
1085
		 ));
1086

    
1087
		 $section->addInput(new Form_Input(
1088
			'act',
1089
			null,
1090
			'hidden',
1091
			'csr'
1092
		 ));
1093
	 }
1094

    
1095
	$form->add($section);
1096

    
1097
	$form->addGlobal(new Form_Button(
1098
		'save',
1099
		'Update',
1100
		null,
1101
		'fa-save'
1102
	))->addClass('btn-primary');
1103

    
1104
	print($form);
1105
} else {
1106
?>
1107
<div class="panel panel-default">
1108
	<div class="panel-heading"><h2 class="panel-title"><?=gettext('Certificates')?></h2></div>
1109
	<div class="panel-body">
1110
		<div class="table-responsive">
1111
		<table class="table table-striped table-hover">
1112
			<thead>
1113
				<tr>
1114
					<th><?=gettext("Name")?></th>
1115
					<th><?=gettext("Issuer")?></th>
1116
					<th><?=gettext("Distinguished Name")?></th>
1117
					<th><?=gettext("In Use")?></th>
1118

    
1119
					<th class="col-sm-2"><?=gettext("Actions")?></th>
1120
				</tr>
1121
			</thead>
1122
			<tbody>
1123
<?php
1124

    
1125
$pluginparams = array();
1126
$pluginparams['type'] = 'certificates';
1127
$pluginparams['event'] = 'used_certificates';
1128
$certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
1129
$i = 0;
1130
foreach ($a_cert as $i => $cert):
1131
	$name = htmlspecialchars($cert['descr']);
1132
	$sans = array();
1133
	if ($cert['crt']) {
1134
		$subj = cert_get_subject($cert['crt']);
1135
		$issuer = cert_get_issuer($cert['crt']);
1136
		$purpose = cert_get_purpose($cert['crt']);
1137
		$sans = cert_get_sans($cert['crt']);
1138
		list($startdate, $enddate) = cert_get_dates($cert['crt']);
1139

    
1140
		if ($subj == $issuer) {
1141
			$caname = '<i>'. gettext("self-signed") .'</i>';
1142
		} else {
1143
			$caname = '<i>'. gettext("external").'</i>';
1144
		}
1145

    
1146
		$subj = htmlspecialchars(cert_escape_x509_chars($subj, true));
1147
	} else {
1148
		$subj = "";
1149
		$issuer = "";
1150
		$purpose = "";
1151
		$startdate = "";
1152
		$enddate = "";
1153
		$caname = "<em>" . gettext("private key only") . "</em>";
1154
	}
1155

    
1156
	if ($cert['csr']) {
1157
		$subj = htmlspecialchars(cert_escape_x509_chars(csr_get_subject($cert['csr']), true));
1158
		$sans = cert_get_sans($cert['crt']);
1159
		$caname = "<em>" . gettext("external - signature pending") . "</em>";
1160
	}
1161

    
1162
	$ca = lookup_ca($cert['caref']);
1163
	if ($ca) {
1164
		$caname = $ca['descr'];
1165
	}
1166
?>
1167
				<tr>
1168
					<td>
1169
						<?=$name?><br />
1170
						<?php if ($cert['type']): ?>
1171
							<i><?=$cert_types[$cert['type']]?></i><br />
1172
						<?php endif?>
1173
						<?php if (is_array($purpose)): ?>
1174
							CA: <b><?=$purpose['ca']?></b><br/>
1175
							<?=gettext("Server")?>: <b><?=$purpose['server']?></b><br/>
1176
						<?php endif?>
1177
					</td>
1178
					<td><?=$caname?></td>
1179
					<td>
1180
						<?=$subj?>
1181
						<?php
1182
						$certextinfo = "";
1183
						$certserial = cert_get_serial($cert['crt']);
1184
						if (!empty($certserial)) {
1185
							$certextinfo .= '<b>' . gettext("Serial: ") . '</b> ';
1186
							$certextinfo .= htmlspecialchars(cert_escape_x509_chars($certserial, true));
1187
							$certextinfo .= '<br/>';
1188
						}
1189
						$certsig = cert_get_sigtype($cert['crt']);
1190
						if (is_array($certsig) && !empty($certsig) && !empty($certsig['shortname'])) {
1191
							$certextinfo .= '<b>' . gettext("Signature Digest: ") . '</b> ';
1192
							$certextinfo .= htmlspecialchars(cert_escape_x509_chars($certsig['shortname'], true));
1193
							$certextinfo .= '<br/>';
1194
						}
1195
						if (is_array($sans) && !empty($sans)) {
1196
							$certextinfo .= '<b>' . gettext("SAN: ") . '</b> ';
1197
							$certextinfo .= htmlspecialchars(implode(', ', cert_escape_x509_chars($sans, true)));
1198
							$certextinfo .= '<br/>';
1199
						}
1200
						if (is_array($purpose) && !empty($purpose['ku'])) {
1201
							$certextinfo .= '<b>' . gettext("KU: ") . '</b> ';
1202
							$certextinfo .= htmlspecialchars(implode(', ', $purpose['ku']));
1203
							$certextinfo .= '<br/>';
1204
						}
1205
						if (is_array($purpose) && !empty($purpose['eku'])) {
1206
							$certextinfo .= '<b>' . gettext("EKU: ") . '</b> ';
1207
							$certextinfo .= htmlspecialchars(implode(', ', $purpose['eku']));
1208
							$certextinfo .= '<br/>';
1209
						}
1210
						if (cert_get_ocspstaple($cert['crt'])) {
1211
							$certextinfo .= '<b>' . gettext("OCSP: ") . '</b> ';
1212
							$certextinfo .= gettext("Must Staple");
1213
						}
1214
						?>
1215
						<?php if (!empty($certextinfo)): ?>
1216
							<div class="infoblock">
1217
							<? print_info_box($certextinfo, 'info', false); ?>
1218
							</div>
1219
						<?php endif?>
1220

    
1221
						<?php if (!empty($startdate) || !empty($enddate)): ?>
1222
						<br />
1223
						<small>
1224
							<?=gettext("Valid From")?>: <b><?=$startdate ?></b><br /><?=gettext("Valid Until")?>: <b><?=$enddate ?></b>
1225
						</small>
1226
						<?php endif?>
1227
					</td>
1228
					<td>
1229
						<?php if (is_cert_revoked($cert)): ?>
1230
							<i><?=gettext("Revoked")?></i>
1231
						<?php endif?>
1232
						<?php if (is_webgui_cert($cert['refid'])): ?>
1233
							<?=gettext("webConfigurator")?>
1234
						<?php endif?>
1235
						<?php if (is_user_cert($cert['refid'])): ?>
1236
							<?=gettext("User Cert")?>
1237
						<?php endif?>
1238
						<?php if (is_openvpn_server_cert($cert['refid'])): ?>
1239
							<?=gettext("OpenVPN Server")?>
1240
						<?php endif?>
1241
						<?php if (is_openvpn_client_cert($cert['refid'])): ?>
1242
							<?=gettext("OpenVPN Client")?>
1243
						<?php endif?>
1244
						<?php if (is_ipsec_cert($cert['refid'])): ?>
1245
							<?=gettext("IPsec Tunnel")?>
1246
						<?php endif?>
1247
						<?php if (is_captiveportal_cert($cert['refid'])): ?>
1248
							<?=gettext("Captive Portal")?>
1249
						<?php endif?>
1250
						<?php echo cert_usedby_description($cert['refid'], $certificates_used_by_packages); ?>
1251
					</td>
1252
					<td>
1253
						<?php if (!$cert['csr']): ?>
1254
							<a href="system_certmanager.php?act=exp&amp;id=<?=$i?>" class="fa fa-certificate" title="<?=gettext("Export Certificate")?>"></a>
1255
							<?php if ($cert['prv']): ?>
1256
								<a href="system_certmanager.php?act=key&amp;id=<?=$i?>" class="fa fa-key" title="<?=gettext("Export Key")?>"></a>
1257
							<?php endif?>
1258
							<a href="system_certmanager.php?act=p12&amp;id=<?=$i?>" class="fa fa-archive" title="<?=gettext("Export P12")?>"></a>
1259
						<?php else: ?>
1260
							<a href="system_certmanager.php?act=csr&amp;id=<?=$i?>" class="fa fa-pencil" title="<?=gettext("Update CSR")?>"></a>
1261
							<a href="system_certmanager.php?act=req&amp;id=<?=$i?>" class="fa fa-sign-in" title="<?=gettext("Export Request")?>"></a>
1262
							<a href="system_certmanager.php?act=key&amp;id=<?=$i?>" class="fa fa-key" title="<?=gettext("Export Key")?>"></a>
1263
						<?php endif?>
1264
						<?php if (!cert_in_use($cert['refid'])): ?>
1265
							<a href="system_certmanager.php?act=del&amp;id=<?=$i?>" class="fa fa-trash" title="<?=gettext("Delete Certificate")?>" usepost></a>
1266
						<?php endif?>
1267
					</td>
1268
				</tr>
1269
<?php
1270
	$i++;
1271
	endforeach; ?>
1272
			</tbody>
1273
		</table>
1274
		</div>
1275
	</div>
1276
</div>
1277

    
1278
<nav class="action-buttons">
1279
	<a href="?act=new" class="btn btn-success btn-sm">
1280
		<i class="fa fa-plus icon-embed-btn"></i>
1281
		<?=gettext("Add/Sign")?>
1282
	</a>
1283
</nav>
1284
<?php
1285
	include("foot.inc");
1286
	exit;
1287
}
1288

    
1289

    
1290
?>
1291
<script type="text/javascript">
1292
//<![CDATA[
1293
events.push(function() {
1294

    
1295
<?php if ($internal_ca_count): ?>
1296
	function internalca_change() {
1297

    
1298
		caref = $('#caref').val();
1299

    
1300
		switch (caref) {
1301
<?php
1302
			foreach ($a_ca as $ca):
1303
				if (!$ca['prv']) {
1304
					continue;
1305
				}
1306

    
1307
				$subject = cert_get_subject_hash($ca['crt']);
1308
?>
1309
				case "<?=$ca['refid'];?>":
1310
					$('#dn_country').val(<?=json_encode(cert_escape_x509_chars($subject['C'], true));?>);
1311
					$('#dn_state').val(<?=json_encode(cert_escape_x509_chars($subject['ST'], true));?>);
1312
					$('#dn_city').val(<?=json_encode(cert_escape_x509_chars($subject['L'], true));?>);
1313
					$('#dn_organization').val(<?=json_encode(cert_escape_x509_chars($subject['O'], true));?>);
1314
					$('#dn_organizationalunit').val(<?=json_encode(cert_escape_x509_chars($subject['OU'], true));?>);
1315
					break;
1316
<?php
1317
			endforeach;
1318
?>
1319
		}
1320
	}
1321

    
1322
	function set_csr_ro() {
1323
		var newcsr = ($('#csrtosign').val() == "new");
1324

    
1325
		$('#csrpaste').attr('readonly', !newcsr);
1326
		$('#keypaste').attr('readonly', !newcsr);
1327
		setRequired('csrpaste', newcsr);
1328
	}
1329

    
1330
	// ---------- Click checkbox handlers ---------------------------------------------------------
1331

    
1332
	$('#caref').on('change', function() {
1333
		internalca_change();
1334
	});
1335

    
1336
	$('#csrtosign').change(function () {
1337
		set_csr_ro();
1338
	});
1339

    
1340
	// ---------- On initial page load ------------------------------------------------------------
1341

    
1342
	internalca_change();
1343
	set_csr_ro();
1344

    
1345
	// Suppress "Delete row" button if there are fewer than two rows
1346
	checkLastRow();
1347

    
1348
<?php endif; ?>
1349

    
1350

    
1351
});
1352
//]]>
1353
</script>
1354
<?php
1355
include('foot.inc');
(201-201/234)