Project

General

Profile

Download (39.5 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
	"import" => gettext("Import an existing Certificate"),
36
	"internal" => gettext("Create an internal Certificate"),
37
	"external" => gettext("Create a Certificate Signing Request"),
38
	"sign" => gettext("Sign a Certificate Signing Request")
39
);
40

    
41
$cert_keylens = array("512", "1024", "2048", "3072", "4096", "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_country dn_state dn_city ".
251
				"dn_organization dn_email dn_commonname");
252
			$reqdfieldsn = array(
253
				gettext("Descriptive name"),
254
				gettext("Certificate authority"),
255
				gettext("Key length"),
256
				gettext("Certificate Type"),
257
				gettext("Lifetime"),
258
				gettext("Distinguished name Country Code"),
259
				gettext("Distinguished name State or Province"),
260
				gettext("Distinguished name City"),
261
				gettext("Distinguished name Organization"),
262
				gettext("Distinguished name Email Address"),
263
				gettext("Distinguished name Common Name"));
264
		}
265

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

    
281
		if ($pconfig['method'] == "existing") {
282
			$reqdfields = array("certref");
283
			$reqdfieldsn = array(gettext("Existing Certificate Choice"));
284
		}
285

    
286
		$altnames = array();
287
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
288

    
289
		if ($pconfig['method'] != "import" && $pconfig['method'] != "existing") {
290
			/* subjectAltNames */
291
			$san_typevar = 'altname_type';
292
			$san_valuevar = 'altname_value';
293
			// This is just the blank alternate name that is added for display purposes. We don't want to validate/save it
294
			if ($_POST["{$san_valuevar}0"] == "") {
295
				unset($_POST["{$san_typevar}0"]);
296
				unset($_POST["{$san_valuevar}0"]);
297
			}
298
			foreach ($_POST as $key => $value) {
299
				$entry = '';
300
				if (!substr_compare($san_typevar, $key, 0, strlen($san_typevar))) {
301
					$entry = substr($key, strlen($san_typevar));
302
					$field = 'type';
303
				} elseif (!substr_compare($san_valuevar, $key, 0, strlen($san_valuevar))) {
304
					$entry = substr($key, strlen($san_valuevar));
305
					$field = 'value';
306
				}
307

    
308
				if (ctype_digit($entry)) {
309
					$entry++;	// Pre-bootstrap code is one-indexed, but the bootstrap code is 0-indexed
310
					$altnames[$entry][$field] = $value;
311
				}
312
			}
313

    
314
			$pconfig['altnames']['item'] = $altnames;
315

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

    
348
			/* Make sure we do not have invalid characters in the fields for the certificate */
349

    
350
			if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
351
				array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
352
			}
353

    
354
			for ($i = 0; $i < count($reqdfields); $i++) {
355
				if (preg_match('/email/', $reqdfields[$i])) { /* dn_email or csr_dn_name */
356
					if (preg_match("/[\!\#\$\%\^\(\)\~\?\>\<\&\/\\\,\"\']/", $_POST[$reqdfields[$i]])) {
357
						array_push($input_errors, gettext("The field 'Distinguished name Email Address' contains invalid characters."));
358
					}
359
				}
360
			}
361

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

    
369
			if (($pconfig['method'] == "external") && isset($_POST["csr_keylen"]) && !in_array($_POST["csr_keylen"], $cert_keylens)) {
370
				array_push($input_errors, gettext("Please select a valid Key Length."));
371
			}
372
			if (($pconfig['method'] == "external") && !in_array($_POST["csr_digest_alg"], $openssl_digest_algs)) {
373
				array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
374
			}
375
			if (($pconfig['method'] == "sign") && !in_array($_POST["csrsign_digest_alg"], $openssl_digest_algs)) {
376
				array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
377
			}
378
		}
379

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

    
383
			if ($pconfig['method'] == "existing") {
384
				$cert = lookup_cert($pconfig['certref']);
385
				if ($cert && $a_user) {
386
					$a_user[$userid]['cert'][] = $cert['refid'];
387
				}
388
			} else if ($pconfig['method'] == "sign") { // Sign a CSR
389
				$csrid = lookup_cert($pconfig['csrtosign']);
390
				$ca = & lookup_ca($pconfig['catosignwith']);
391

    
392
				// Read the CSR from $config, or if a new one, from the textarea
393
				if ($pconfig['csrtosign'] === "new") {
394
					$csr = $pconfig['csrpaste'];
395
				} else {
396
					$csr = base64_decode($csrid['csr']);
397
				}
398
				if (count($altnames)) {
399
					foreach ($altnames as $altname) {
400
						$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
401
					}
402
					$altname_str = implode(",", $altnames_tmp);
403
				}
404

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

    
407
				if ($n509) {
408
					// Gather the details required to save the new cert
409
					$newcert = array();
410
					$newcert['refid'] = uniqid();
411
					$newcert['caref'] = $pconfig['catosignwith'];
412
					$newcert['descr'] = $pconfig['descr'];
413
					$newcert['type'] = $pconfig['type'];
414
					$newcert['crt'] = base64_encode($n509);
415

    
416
					if ($pconfig['csrtosign'] === "new") {
417
						$newcert['prv'] = base64_encode($pconfig['keypaste']);
418
					} else {
419
						$newcert['prv'] = $csrid['prv'];
420
					}
421

    
422
					// Add it to the config file
423
					$config['cert'][] = $newcert;
424
				}
425

    
426
			} else {
427
				$cert = array();
428
				$cert['refid'] = uniqid();
429
				if (isset($id) && $a_cert[$id]) {
430
					$cert = $a_cert[$id];
431
				}
432

    
433
				$cert['descr'] = $pconfig['descr'];
434

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

    
437
				if ($pconfig['method'] == "import") {
438
					cert_import($cert, $pconfig['cert'], $pconfig['key']);
439
				}
440

    
441
				if ($pconfig['method'] == "internal") {
442
					$dn = array(
443
						'countryName' => $pconfig['dn_country'],
444
						'stateOrProvinceName' => cert_escape_x509_chars($pconfig['dn_state']),
445
						'localityName' => cert_escape_x509_chars($pconfig['dn_city']),
446
						'organizationName' => cert_escape_x509_chars($pconfig['dn_organization']),
447
						'emailAddress' => cert_escape_x509_chars($pconfig['dn_email']),
448
						'commonName' => cert_escape_x509_chars($pconfig['dn_commonname']));
449
					if (!empty($pconfig['dn_organizationalunit'])) {
450
						$dn['organizationalUnitName'] = cert_escape_x509_chars($pconfig['dn_organizationalunit']);
451
					}
452

    
453
					$altnames_tmp = array();
454
					$cn_altname = cert_add_altname_type($pconfig['dn_commonname']);
455
					if (!empty($cn_altname)) {
456
						$altnames_tmp[] = $cn_altname;
457
					}
458
					if (count($altnames)) {
459
						foreach ($altnames as $altname) {
460
							// The CN is added as a SAN automatically, do not add it again.
461
							if ($altname['value'] != $pconfig['dn_commonname']) {
462
								$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
463
							}
464
						}
465
					}
466
					if (!empty($altnames_tmp)) {
467
						$dn['subjectAltName'] = implode(",", $altnames_tmp);
468
					}
469

    
470
					if (!cert_create($cert, $pconfig['caref'], $pconfig['keylen'], $pconfig['lifetime'], $dn, $pconfig['type'], $pconfig['digest_alg'])) {
471
						$input_errors = array();
472
						while ($ssl_err = openssl_error_string()) {
473
							if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
474
								array_push($input_errors, "openssl library returns: " . $ssl_err);
475
							}
476
						}
477
					}
478
				}
479

    
480
				if ($pconfig['method'] == "external") {
481
					$dn = array(
482
						'countryName' => $pconfig['csr_dn_country'],
483
						'stateOrProvinceName' => cert_escape_x509_chars($pconfig['csr_dn_state']),
484
						'localityName' => cert_escape_x509_chars($pconfig['csr_dn_city']),
485
						'organizationName' => cert_escape_x509_chars($pconfig['csr_dn_organization']),
486
						'emailAddress' => cert_escape_x509_chars($pconfig['csr_dn_email']),
487
						'commonName' => cert_escape_x509_chars($pconfig['csr_dn_commonname']));
488
					if (!empty($pconfig['csr_dn_organizationalunit'])) {
489
						$dn['organizationalUnitName'] = cert_escape_x509_chars($pconfig['csr_dn_organizationalunit']);
490
					}
491

    
492
					$altnames_tmp = array();
493
					$cn_altname = cert_add_altname_type($pconfig['csr_dn_commonname']);
494
					if (!empty($cn_altname)) {
495
						$altnames_tmp[] = $cn_altname;
496
					}
497
					if (count($altnames)) {
498
						foreach ($altnames as $altname) {
499
							// The CN is added as a SAN automatically, do not add it again.
500
							if ($altname['value'] != $pconfig['csr_dn_commonname']) {
501
								$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
502
							}
503
						}
504
					}
505
					if (!empty($altnames_tmp)) {
506
						$dn['subjectAltName'] = implode(",", $altnames_tmp);
507
					}
508

    
509
					if (!csr_generate($cert, $pconfig['csr_keylen'], $dn, $pconfig['type'], $pconfig['csr_digest_alg'])) {
510
						$input_errors = array();
511
						while ($ssl_err = openssl_error_string()) {
512
							if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
513
								array_push($input_errors, "openssl library returns: " . $ssl_err);
514
							}
515
						}
516
					}
517
				}
518

    
519
				error_reporting($old_err_level);
520

    
521
				if (isset($id) && $a_cert[$id]) {
522
					$a_cert[$id] = $cert;
523
				} else {
524
					$a_cert[] = $cert;
525
				}
526

    
527
				if (isset($a_user) && isset($userid)) {
528
					$a_user[$userid]['cert'][] = $cert['refid'];
529
				}
530
			}
531

    
532
			if (!$input_errors) {
533
				write_config();
534
			}
535

    
536
			if ($userid && !$input_errors) {
537
				post_redirect("system_usermanager.php", array('act' => 'edit', 'userid' => $userid));
538
				exit;
539
			}
540
		}
541
	}
542

    
543
	if ($_POST['save'] == gettext("Update")) {
544
		unset($input_errors);
545
		$pconfig = $_POST;
546

    
547
		/* input validation */
548
		$reqdfields = explode(" ", "descr cert");
549
		$reqdfieldsn = array(
550
			gettext("Descriptive name"),
551
			gettext("Final Certificate data"));
552

    
553
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
554

    
555
		if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
556
			array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
557
		}
558

    
559
//		old way
560
		/* make sure this csr and certificate subjects match */
561
//		$subj_csr = csr_get_subject($pconfig['csr'], false);
562
//		$subj_cert = cert_get_subject($pconfig['cert'], false);
563
//
564
//		if (!isset($_POST['ignoresubjectmismatch']) && !($_POST['ignoresubjectmismatch'] == "yes")) {
565
//			if (strcmp($subj_csr, $subj_cert)) {
566
//				$input_errors[] = sprintf(gettext("The certificate subject '%s' does not match the signing request subject."), $subj_cert);
567
//				$subject_mismatch = true;
568
//			}
569
//		}
570
		$mod_csr = cert_get_publickey($pconfig['csr'], false, 'csr');
571
		$mod_cert = cert_get_publickey($pconfig['cert'], false);
572

    
573
		if (strcmp($mod_csr, $mod_cert)) {
574
			// simply: if the moduli don't match, then the private key and public key won't match
575
			$input_errors[] = sprintf(gettext("The certificate public key does not match the signing request public key."), $subj_cert);
576
			$subject_mismatch = true;
577
		}
578

    
579
		/* save modifications */
580
		if (!$input_errors) {
581

    
582
			$cert = $a_cert[$id];
583

    
584
			$cert['descr'] = $pconfig['descr'];
585

    
586
			csr_complete($cert, $pconfig['cert']);
587

    
588
			$a_cert[$id] = $cert;
589

    
590
			write_config();
591

    
592
			pfSenseHeader("system_certmanager.php");
593
		}
594
	}
595
}
596

    
597
$pgtitle = array(gettext("System"), gettext("Certificate Manager"), gettext("Certificates"));
598
$pglinks = array("", "system_camanager.php", "system_certmanager.php");
599

    
600
if (($act == "new" || ($_POST['save'] == gettext("Save") && $input_errors)) || ($act == "csr" || ($_POST['save'] == gettext("Update") && $input_errors))) {
601
	$pgtitle[] = gettext('Edit');
602
	$pglinks[] = "@self";
603
}
604
include("head.inc");
605

    
606
if ($input_errors) {
607
	print_input_errors($input_errors);
608
}
609

    
610
if ($savemsg) {
611
	print_info_box($savemsg, 'success');
612
}
613

    
614
$tab_array = array();
615
$tab_array[] = array(gettext("CAs"), false, "system_camanager.php");
616
$tab_array[] = array(gettext("Certificates"), true, "system_certmanager.php");
617
$tab_array[] = array(gettext("Certificate Revocation"), false, "system_crlmanager.php");
618
display_top_tabs($tab_array);
619

    
620
// Load valid country codes
621
$dn_cc = array();
622
if (file_exists("/etc/ca_countries")) {
623
	$dn_cc_file=file("/etc/ca_countries");
624
	foreach ($dn_cc_file as $line) {
625
		if (preg_match('/^(\S*)\s(.*)$/', $line, $matches)) {
626
			$dn_cc[$matches[1]] = $matches[1];
627
		}
628
	}
629
}
630

    
631
if ($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)) {
632
	$form = new Form();
633
	$form->setAction('system_certmanager.php?act=edit');
634

    
635
	if (isset($userid) && $a_user) {
636
		$form->addGlobal(new Form_Input(
637
			'userid',
638
			null,
639
			'hidden',
640
			$userid
641
		));
642
	}
643

    
644
	if (isset($id) && $a_cert[$id]) {
645
		$form->addGlobal(new Form_Input(
646
			'id',
647
			null,
648
			'hidden',
649
			$id
650
		));
651
	}
652

    
653
	$section = new Form_Section('Add/Sign a New Certificate');
654

    
655
	if (!isset($id)) {
656
		$section->addInput(new Form_Select(
657
			'method',
658
			'*Method',
659
			$pconfig['method'],
660
			$cert_methods
661
		))->toggles();
662
	}
663

    
664
	$section->addInput(new Form_Input(
665
		'descr',
666
		'*Descriptive name',
667
		'text',
668
		($a_user && empty($pconfig['descr'])) ? $a_user[$userid]['name'] : $pconfig['descr']
669
	))->addClass('toggle-existing');
670

    
671
	$form->add($section);
672

    
673
	// Return an array containing the IDs od all CAs
674
	function list_cas() {
675
		global $a_ca;
676
		$allCas = array();
677

    
678
		foreach ($a_ca as $ca) {
679
			if ($ca['prv']) {
680
				$allCas[$ca['refid']] = $ca['descr'];
681
			}
682
		}
683

    
684
		return $allCas;
685
	}
686

    
687
	// Return an array containing the IDs od all CSRs
688
	function list_csrs() {
689
		global $config;
690
		$allCsrs = array();
691

    
692
		foreach ($config['cert'] as $cert) {
693
			if ($cert['csr']) {
694
				$allCsrs[$cert['refid']] = $cert['descr'];
695
			}
696
		}
697

    
698
		return ['new' => gettext('New CSR (Paste below)')] + $allCsrs;
699
	}
700

    
701
	$section = new Form_Section('Sign CSR');
702
	$section->addClass('toggle-sign collapse');
703

    
704
	$section->AddInput(new Form_Select(
705
		'catosignwith',
706
		'*CA to sign with',
707
		$pconfig['catosignwith'],
708
		list_cas()
709
	));
710

    
711
	$section->AddInput(new Form_Select(
712
		'csrtosign',
713
		'*CSR to sign',
714
		isset($pconfig['csrtosign']) ? $pconfig['csrtosign'] : 'new',
715
		list_csrs()
716
	));
717

    
718
	$section->addInput(new Form_Textarea(
719
		'csrpaste',
720
		'CSR data',
721
		$pconfig['csrpaste']
722
	))->setHelp('Paste a Certificate Signing Request in X.509 PEM format here.');
723

    
724
	$section->addInput(new Form_Textarea(
725
		'keypaste',
726
		'Key data',
727
		$pconfig['keypaste']
728
	))->setHelp('Optionally paste a private key here. The key will be associated with the newly signed certificate in pfSense');
729

    
730
	$section->addInput(new Form_Input(
731
		'csrsign_lifetime',
732
		'*Certificate Lifetime (days)',
733
		'number',
734
		$pconfig['csrsign_lifetime'] ? $pconfig['csrsign_lifetime']:'3650'
735
	));
736
	$section->addInput(new Form_Select(
737
		'csrsign_digest_alg',
738
		'*Digest Algorithm',
739
		$pconfig['csrsign_digest_alg'],
740
		array_combine($openssl_digest_algs, $openssl_digest_algs)
741
	))->setHelp('NOTE: It is recommended to use an algorithm stronger than '.
742
		'SHA1 when possible');
743

    
744
	$form->add($section);
745

    
746
	$section = new Form_Section('Import Certificate');
747
	$section->addClass('toggle-import collapse');
748

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

    
755
	$section->addInput(new Form_Textarea(
756
		'key',
757
		'*Private key data',
758
		$pconfig['key']
759
	))->setHelp('Paste a private key in X.509 PEM format here.');
760

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

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

    
779
			$allCas[ $ca['refid'] ] = $ca['descr'];
780
		}
781

    
782
		$section->addInput(new Form_Select(
783
			'caref',
784
			'*Certificate authority',
785
			$pconfig['caref'],
786
			$allCas
787
		));
788
	}
789

    
790
	$section->addInput(new Form_Select(
791
		'keylen',
792
		'*Key length',
793
		$pconfig['keylen'],
794
		array_combine($cert_keylens, $cert_keylens)
795
	));
796

    
797
	$section->addInput(new Form_Select(
798
		'digest_alg',
799
		'*Digest Algorithm',
800
		$pconfig['digest_alg'],
801
		array_combine($openssl_digest_algs, $openssl_digest_algs)
802
	))->setHelp('NOTE: It is recommended to use an algorithm stronger than '.
803
		'SHA1 when possible.');
804

    
805
	$section->addInput(new Form_Input(
806
		'lifetime',
807
		'*Lifetime (days)',
808
		'number',
809
		$pconfig['lifetime']
810
	));
811

    
812
	$section->addInput(new Form_Select(
813
		'dn_country',
814
		'*Country Code',
815
		$pconfig['dn_country'],
816
		$dn_cc
817
	));
818

    
819
	$section->addInput(new Form_Input(
820
		'dn_state',
821
		'*State or Province',
822
		'text',
823
		$pconfig['dn_state'],
824
		['placeholder' => 'e.g. Texas']
825
	));
826

    
827
	$section->addInput(new Form_Input(
828
		'dn_city',
829
		'*City',
830
		'text',
831
		$pconfig['dn_city'],
832
		['placeholder' => 'e.g. Austin']
833
	));
834

    
835
	$section->addInput(new Form_Input(
836
		'dn_organization',
837
		'*Organization',
838
		'text',
839
		$pconfig['dn_organization'],
840
		['placeholder' => 'e.g. My Company Inc']
841
	));
842

    
843
	$section->addInput(new Form_Input(
844
		'dn_organizationalunit',
845
		'Organizational Unit',
846
		'text',
847
		$pconfig['dn_organizationalunit'],
848
		['placeholder' => 'e.g. My Department Name (optional)']
849
	));
850

    
851
	$section->addInput(new Form_Input(
852
		'dn_email',
853
		'*Email Address',
854
		'text',
855
		$pconfig['dn_email'],
856
		['placeholder' => 'e.g. admin@mycompany.com']
857
	));
858

    
859
	$section->addInput(new Form_Input(
860
		'dn_commonname',
861
		'*Common Name',
862
		'text',
863
		$pconfig['dn_commonname'],
864
		['placeholder' => 'e.g. www.example.com']
865
	));
866

    
867
	$form->add($section);
868
	$section = new Form_Section('External Signing Request');
869
	$section->addClass('toggle-external collapse');
870

    
871
	$section->addInput(new Form_Select(
872
		'csr_keylen',
873
		'*Key length',
874
		$pconfig['csr_keylen'],
875
		array_combine($cert_keylens, $cert_keylens)
876
	));
877

    
878
	$section->addInput(new Form_Select(
879
		'csr_digest_alg',
880
		'*Digest Algorithm',
881
		$pconfig['csr_digest_alg'],
882
		array_combine($openssl_digest_algs, $openssl_digest_algs)
883
	))->setHelp('NOTE: It is recommended to use an algorithm stronger than '.
884
		'SHA1 when possible');
885

    
886
	$section->addInput(new Form_Select(
887
		'csr_dn_country',
888
		'*Country Code',
889
		$pconfig['csr_dn_country'],
890
		$dn_cc
891
	));
892

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

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

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

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

    
925
	$section->addInput(new Form_Input(
926
		'csr_dn_email',
927
		'*Email Address',
928
		'text',
929
		$pconfig['csr_dn_email'],
930
		['placeholder' => 'e.g. admin@mycompany.com']
931
	));
932

    
933
	$section->addInput(new Form_Input(
934
		'csr_dn_commonname',
935
		'*Common Name',
936
		'text',
937
		$pconfig['csr_dn_commonname'],
938
		['placeholder' => 'e.g. internal-ca']
939
	));
940

    
941
	$form->add($section);
942
	$section = new Form_Section('Choose an Existing Certificate');
943
	$section->addClass('toggle-existing collapse');
944

    
945
	$existCerts = array();
946

    
947
	foreach ($config['cert'] as $cert)	{
948
		if (is_array($config['system']['user'][$userid]['cert'])) { // Could be MIA!
949
			if (isset($userid) && in_array($cert['refid'], $config['system']['user'][$userid]['cert'])) {
950
				continue;
951
			}
952
		}
953

    
954
		$ca = lookup_ca($cert['caref']);
955
		if ($ca) {
956
			$cert['descr'] .= " (CA: {$ca['descr']})";
957
		}
958

    
959
		if (cert_in_use($cert['refid'])) {
960
			$cert['descr'] .= " (In Use)";
961
		}
962
		if (is_cert_revoked($cert)) {
963
			$cert['descr'] .= " (Revoked)";
964
		}
965

    
966
		$existCerts[ $cert['refid'] ] = $cert['descr'];
967
	}
968

    
969
	$section->addInput(new Form_Select(
970
		'certref',
971
		'*Existing Certificates',
972
		$pconfig['certref'],
973
		$existCerts
974
	));
975

    
976
	$form->add($section);
977

    
978
	$section = new Form_Section('Certificate Attributes');
979
	$section->addClass('toggle-external toggle-internal toggle-sign collapse');
980

    
981
	$section->addInput(new Form_StaticText(
982
		gettext('Attribute Notes'),
983
		'<span class="help-block">'.
984
		gettext('The following attributes are added to certificates and ' .
985
		'requests when they are created or signed. These attributes behave ' .
986
		'differently depending on the selected mode.') .
987
		'<br/><br/>' .
988
		'<span class="toggle-internal collapse">' . gettext('For Internal Certificates, these attributes are added directly to the certificate as shown.') . '</span>' .
989
		'<span class="toggle-external collapse">' .
990
		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. ') .
991
		'<br/><br/>' .
992
		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>' .
993
		'<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>' .
994
		'</span>'
995
	));
996

    
997
	$section->addInput(new Form_Select(
998
		'type',
999
		'*Certificate Type',
1000
		$pconfig['type'],
1001
		$cert_types
1002
	))->setHelp('Add type-specific usage attributes to the signed certificate.' .
1003
		' Used for placing usage restrictions on, or granting abilities to, ' .
1004
		'the signed certificate.');
1005

    
1006
	if (empty($pconfig['altnames']['item'])) {
1007
		$pconfig['altnames']['item'] = array(
1008
			array('type' => null, 'value' => null)
1009
		);
1010
	}
1011

    
1012
	$counter = 0;
1013
	$numrows = count($pconfig['altnames']['item']) - 1;
1014

    
1015
	foreach ($pconfig['altnames']['item'] as $item) {
1016

    
1017
		$group = new Form_Group($counter == 0 ? 'Alternative Names':'');
1018

    
1019
		$group->add(new Form_Select(
1020
			'altname_type' . $counter,
1021
			'Type',
1022
			$item['type'],
1023
			$cert_altname_types
1024
		))->setHelp(($counter == $numrows) ? 'Type':null);
1025

    
1026
		$group->add(new Form_Input(
1027
			'altname_value' . $counter,
1028
			null,
1029
			'text',
1030
			$item['value']
1031
		))->setHelp(($counter == $numrows) ? 'Value':null);
1032

    
1033
		$group->add(new Form_Button(
1034
			'deleterow' . $counter,
1035
			'Delete',
1036
			null,
1037
			'fa-trash'
1038
		))->addClass('btn-warning');
1039

    
1040
		$group->addClass('repeatable');
1041

    
1042
		$group->setHelp('Enter additional identifiers for the certificate ' .
1043
			'in this list. The Common Name field is automatically ' .
1044
			'added to the certificate as an Alternative Name. ' .
1045
			'The signing CA may ignore or change these values.');
1046

    
1047
		$section->add($group);
1048

    
1049
		$counter++;
1050
	}
1051

    
1052
	$section->addInput(new Form_Button(
1053
		'addrow',
1054
		'Add',
1055
		null,
1056
		'fa-plus'
1057
	))->addClass('btn-success');
1058

    
1059
	$form->add($section);
1060

    
1061

    
1062
	print $form;
1063

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

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

    
1070
	$section->addInput(new Form_Input(
1071
		'descr',
1072
		'*Descriptive name',
1073
		'text',
1074
		$pconfig['descr']
1075
	));
1076

    
1077
	$section->addInput(new Form_Textarea(
1078
		'csr',
1079
		'Signing request data',
1080
		$pconfig['csr']
1081
	))->setReadonly()
1082
	  ->setWidth(7)
1083
	  ->setHelp('Copy the certificate signing data from here and forward it to a certificate authority for signing.');
1084

    
1085
	$section->addInput(new Form_Textarea(
1086
		'cert',
1087
		'*Final certificate data',
1088
		$pconfig['cert']
1089
	))->setWidth(7)
1090
	  ->setHelp('Paste the certificate received from the certificate authority here.');
1091

    
1092
	 if (isset($id) && $a_cert[$id]) {
1093
		 $section->addInput(new Form_Input(
1094
			'id',
1095
			null,
1096
			'hidden',
1097
			$id
1098
		 ));
1099

    
1100
		 $section->addInput(new Form_Input(
1101
			'act',
1102
			null,
1103
			'hidden',
1104
			'csr'
1105
		 ));
1106
	 }
1107

    
1108
	$form->add($section);
1109

    
1110
	$form->addGlobal(new Form_Button(
1111
		'save',
1112
		'Update',
1113
		null,
1114
		'fa-save'
1115
	))->addClass('btn-primary');
1116

    
1117
	print($form);
1118
} else {
1119
?>
1120
<div class="panel panel-default">
1121
	<div class="panel-heading"><h2 class="panel-title"><?=gettext('Certificates')?></h2></div>
1122
	<div class="panel-body">
1123
		<div class="table-responsive">
1124
		<table class="table table-striped table-hover">
1125
			<thead>
1126
				<tr>
1127
					<th><?=gettext("Name")?></th>
1128
					<th><?=gettext("Issuer")?></th>
1129
					<th><?=gettext("Distinguished Name")?></th>
1130
					<th><?=gettext("In Use")?></th>
1131

    
1132
					<th class="col-sm-2"><?=gettext("Actions")?></th>
1133
				</tr>
1134
			</thead>
1135
			<tbody>
1136
<?php
1137

    
1138
$pluginparams = array();
1139
$pluginparams['type'] = 'certificates';
1140
$pluginparams['event'] = 'used_certificates';
1141
$certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
1142
$i = 0;
1143
foreach ($a_cert as $i => $cert):
1144
	$name = htmlspecialchars($cert['descr']);
1145
	$sans = array();
1146
	if ($cert['crt']) {
1147
		$subj = cert_get_subject($cert['crt']);
1148
		$issuer = cert_get_issuer($cert['crt']);
1149
		$purpose = cert_get_purpose($cert['crt']);
1150
		$sans = cert_get_sans($cert['crt']);
1151
		list($startdate, $enddate) = cert_get_dates($cert['crt']);
1152

    
1153
		if ($subj == $issuer) {
1154
			$caname = '<i>'. gettext("self-signed") .'</i>';
1155
		} else {
1156
			$caname = '<i>'. gettext("external").'</i>';
1157
		}
1158

    
1159
		$subj = htmlspecialchars(cert_escape_x509_chars($subj, true));
1160
	} else {
1161
		$subj = "";
1162
		$issuer = "";
1163
		$purpose = "";
1164
		$startdate = "";
1165
		$enddate = "";
1166
		$caname = "<em>" . gettext("private key only") . "</em>";
1167
	}
1168

    
1169
	if ($cert['csr']) {
1170
		$subj = htmlspecialchars(cert_escape_x509_chars(csr_get_subject($cert['csr']), true));
1171
		$sans = cert_get_sans($cert['crt']);
1172
		$caname = "<em>" . gettext("external - signature pending") . "</em>";
1173
	}
1174

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

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

    
1291
<nav class="action-buttons">
1292
	<a href="?act=new" class="btn btn-success btn-sm">
1293
		<i class="fa fa-plus icon-embed-btn"></i>
1294
		<?=gettext("Add/Sign")?>
1295
	</a>
1296
</nav>
1297
<?php
1298
	include("foot.inc");
1299
	exit;
1300
}
1301

    
1302

    
1303
?>
1304
<script type="text/javascript">
1305
//<![CDATA[
1306
events.push(function() {
1307

    
1308
<?php if ($internal_ca_count): ?>
1309
	function internalca_change() {
1310

    
1311
		caref = $('#caref').val();
1312

    
1313
		switch (caref) {
1314
<?php
1315
			foreach ($a_ca as $ca):
1316
				if (!$ca['prv']) {
1317
					continue;
1318
				}
1319

    
1320
				$subject = cert_get_subject_array($ca['crt']);
1321
?>
1322
				case "<?=$ca['refid'];?>":
1323
					$('#dn_country').val(<?=json_encode(cert_escape_x509_chars($subject[0]['v'], true));?>);
1324
					$('#dn_state').val(<?=json_encode(cert_escape_x509_chars($subject[1]['v'], true));?>);
1325
					$('#dn_city').val(<?=json_encode(cert_escape_x509_chars($subject[2]['v'], true));?>);
1326
					$('#dn_organization').val(<?=json_encode(cert_escape_x509_chars($subject[3]['v'], true));?>);
1327
					$('#dn_email').val(<?=json_encode(cert_escape_x509_chars($subject[4]['v'], true));?>);
1328
					$('#dn_organizationalunit').val(<?=json_encode(cert_escape_x509_chars($subject[6]['v'], true));?>);
1329
					break;
1330
<?php
1331
			endforeach;
1332
?>
1333
		}
1334
	}
1335

    
1336
	function set_csr_ro() {
1337
		var newcsr = ($('#csrtosign').val() == "new");
1338

    
1339
		$('#csrpaste').attr('readonly', !newcsr);
1340
		$('#keypaste').attr('readonly', !newcsr);
1341
		setRequired('csrpaste', newcsr);
1342
	}
1343

    
1344
	// ---------- Click checkbox handlers ---------------------------------------------------------
1345

    
1346
	$('#caref').on('change', function() {
1347
		internalca_change();
1348
	});
1349

    
1350
	$('#csrtosign').change(function () {
1351
		set_csr_ro();
1352
	});
1353

    
1354
	// ---------- On initial page load ------------------------------------------------------------
1355

    
1356
	internalca_change();
1357
	set_csr_ro();
1358

    
1359
	// Suppress "Delete row" button if there are fewer than two rows
1360
	checkLastRow();
1361

    
1362
<?php endif; ?>
1363

    
1364

    
1365
});
1366
//]]>
1367
</script>
1368
<?php
1369
include('foot.inc');
(199-199/232)