Project

General

Profile

Download (38.8 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($cert) || empty($cert)) {
936
			continue;
937
		}
938
		if (is_array($config['system']['user'][$userid]['cert'])) { // Could be MIA!
939
			if (isset($userid) && in_array($cert['refid'], $config['system']['user'][$userid]['cert'])) {
940
				continue;
941
			}
942
		}
943

    
944
		$ca = lookup_ca($cert['caref']);
945
		if ($ca) {
946
			$cert['descr'] .= " (CA: {$ca['descr']})";
947
		}
948

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

    
956
		$existCerts[ $cert['refid'] ] = $cert['descr'];
957
	}
958

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

    
966
	$form->add($section);
967

    
968
	$section = new Form_Section('Certificate Attributes');
969
	$section->addClass('toggle-external toggle-internal toggle-sign collapse');
970

    
971
	$section->addInput(new Form_StaticText(
972
		gettext('Attribute Notes'),
973
		'<span class="help-block">'.
974
		gettext('The following attributes are added to certificates and ' .
975
		'requests when they are created or signed. These attributes behave ' .
976
		'differently depending on the selected mode.') .
977
		'<br/><br/>' .
978
		'<span class="toggle-internal collapse">' . gettext('For Internal Certificates, these attributes are added directly to the certificate as shown.') . '</span>' .
979
		'<span class="toggle-external collapse">' .
980
		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. ') .
981
		'<br/><br/>' .
982
		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>' .
983
		'<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>' .
984
		'</span>'
985
	));
986

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

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

    
1002
	$counter = 0;
1003
	$numrows = count($pconfig['altnames']['item']) - 1;
1004

    
1005
	foreach ($pconfig['altnames']['item'] as $item) {
1006

    
1007
		$group = new Form_Group($counter == 0 ? 'Alternative Names':'');
1008

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

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

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

    
1030
		$group->addClass('repeatable');
1031

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

    
1037
		$section->add($group);
1038

    
1039
		$counter++;
1040
	}
1041

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

    
1049
	$form->add($section);
1050

    
1051

    
1052
	print $form;
1053

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

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

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

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

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

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

    
1090
		 $section->addInput(new Form_Input(
1091
			'act',
1092
			null,
1093
			'hidden',
1094
			'csr'
1095
		 ));
1096
	 }
1097

    
1098
	$form->add($section);
1099

    
1100
	$form->addGlobal(new Form_Button(
1101
		'save',
1102
		'Update',
1103
		null,
1104
		'fa-save'
1105
	))->addClass('btn-primary');
1106

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

    
1122
					<th class="col-sm-2"><?=gettext("Actions")?></th>
1123
				</tr>
1124
			</thead>
1125
			<tbody>
1126
<?php
1127

    
1128
$pluginparams = array();
1129
$pluginparams['type'] = 'certificates';
1130
$pluginparams['event'] = 'used_certificates';
1131
$certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
1132
$i = 0;
1133
foreach ($a_cert as $i => $cert):
1134
	if (!is_array($cert) || empty($cert)) {
1135
		continue;
1136
	}
1137
	$name = htmlspecialchars($cert['descr']);
1138
	$sans = array();
1139
	if ($cert['crt']) {
1140
		$subj = cert_get_subject($cert['crt']);
1141
		$issuer = cert_get_issuer($cert['crt']);
1142
		$purpose = cert_get_purpose($cert['crt']);
1143
		$sans = cert_get_sans($cert['crt']);
1144
		list($startdate, $enddate) = cert_get_dates($cert['crt']);
1145

    
1146
		if ($subj == $issuer) {
1147
			$caname = '<i>'. gettext("self-signed") .'</i>';
1148
		} else {
1149
			$caname = '<i>'. gettext("external").'</i>';
1150
		}
1151

    
1152
		$subj = htmlspecialchars(cert_escape_x509_chars($subj, true));
1153
	} else {
1154
		$subj = "";
1155
		$issuer = "";
1156
		$purpose = "";
1157
		$startdate = "";
1158
		$enddate = "";
1159
		$caname = "<em>" . gettext("private key only") . "</em>";
1160
	}
1161

    
1162
	if ($cert['csr']) {
1163
		$subj = htmlspecialchars(cert_escape_x509_chars(csr_get_subject($cert['csr']), true));
1164
		$sans = cert_get_sans($cert['crt']);
1165
		$caname = "<em>" . gettext("external - signature pending") . "</em>";
1166
	}
1167

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

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

    
1284
<nav class="action-buttons">
1285
	<a href="?act=new" class="btn btn-success btn-sm">
1286
		<i class="fa fa-plus icon-embed-btn"></i>
1287
		<?=gettext("Add/Sign")?>
1288
	</a>
1289
</nav>
1290
<?php
1291
	include("foot.inc");
1292
	exit;
1293
}
1294

    
1295

    
1296
?>
1297
<script type="text/javascript">
1298
//<![CDATA[
1299
events.push(function() {
1300

    
1301
<?php if ($internal_ca_count): ?>
1302
	function internalca_change() {
1303

    
1304
		caref = $('#caref').val();
1305

    
1306
		switch (caref) {
1307
<?php
1308
			foreach ($a_ca as $ca):
1309
				if (!$ca['prv']) {
1310
					continue;
1311
				}
1312

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

    
1328
	function set_csr_ro() {
1329
		var newcsr = ($('#csrtosign').val() == "new");
1330

    
1331
		$('#csrpaste').attr('readonly', !newcsr);
1332
		$('#keypaste').attr('readonly', !newcsr);
1333
		setRequired('csrpaste', newcsr);
1334
	}
1335

    
1336
	// ---------- Click checkbox handlers ---------------------------------------------------------
1337

    
1338
	$('#caref').on('change', function() {
1339
		internalca_change();
1340
	});
1341

    
1342
	$('#csrtosign').change(function () {
1343
		set_csr_ro();
1344
	});
1345

    
1346
	// ---------- On initial page load ------------------------------------------------------------
1347

    
1348
	internalca_change();
1349
	set_csr_ro();
1350

    
1351
	// Suppress "Delete row" button if there are fewer than two rows
1352
	checkLastRow();
1353

    
1354
<?php endif; ?>
1355

    
1356

    
1357
});
1358
//]]>
1359
</script>
1360
<?php
1361
include('foot.inc');
(201-201/234)