Project

General

Profile

Download (54.9 KB) Statistics
| Branch: | Tag: | Revision:
1 64cc39d3 Matthew Grooms
<?php
2
/*
3 c5d81585 Renato Botelho
 * system_certmanager.php
4 98402844 Stephen Beaver
 *
5 c5d81585 Renato Botelho
 * part of pfSense (https://www.pfsense.org)
6 38809d47 Renato Botelho do Couto
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8 402c98a2 Reid Linnemann
 * Copyright (c) 2014-2023 Rubicon Communications, LLC (Netgate)
9 c5d81585 Renato Botelho
 * Copyright (c) 2008 Shrew Soft Inc
10
 * All rights reserved.
11 98402844 Stephen Beaver
 *
12 b12ea3fb Renato Botelho
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15 98402844 Stephen Beaver
 *
16 b12ea3fb Renato Botelho
 * http://www.apache.org/licenses/LICENSE-2.0
17 98402844 Stephen Beaver
 *
18 b12ea3fb Renato Botelho
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23 98402844 Stephen Beaver
 */
24 64cc39d3 Matthew Grooms
25
##|+PRIV
26
##|*IDENT=page-system-certmanager
27
##|*NAME=System: Certificate Manager
28
##|*DESCR=Allow access to the 'System: Certificate Manager' page.
29
##|*MATCH=system_certmanager.php*
30
##|-PRIV
31
32 c81ef6e2 Phil Davis
require_once("guiconfig.inc");
33 14f5ae08 Ermal Lu?i
require_once("certs.inc");
34 fdd8fafc doktornotor
require_once("pfsense-utils.inc");
35 64cc39d3 Matthew Grooms
36
$cert_methods = array(
37 a37753d7 Vinicius Coque
	"internal" => gettext("Create an internal Certificate"),
38 b0a5c280 jim-p
	"import" => gettext("Import an existing Certificate"),
39 ad9b5c67 jim-p
	"external" => gettext("Create a Certificate Signing Request"),
40 2052d3e2 Steve Beaver
	"sign" => gettext("Sign a Certificate Signing Request")
41 ad9b5c67 jim-p
);
42 64cc39d3 Matthew Grooms
43 36cfae5f Justin Coffman
$cert_keylens = array("1024", "2048", "3072", "4096", "6144", "7680", "8192", "15360", "16384");
44 47c46bbd Viktor Gurov
$cert_keytypes = array("RSA", "ECDSA");
45 56b1ed39 Phil Davis
$cert_types = array(
46
	"server" => "Server Certificate",
47
	"user" => "User Certificate");
48 64cc39d3 Matthew Grooms
49 2e1809dd jim-p
global $cert_altname_types;
50 84141846 jim-p
global $openssl_digest_algs;
51 3f0b7bc3 jim-p
global $cert_strict_values;
52 a7e50981 jim-p
global $p12_encryption_levels;
53
54 3a877e4a jim-p
$max_lifetime = cert_get_max_lifetime();
55
$default_lifetime = min(3650, $max_lifetime);
56 cffcf9bf jim-p
$openssl_ecnames = cert_build_curve_list();
57 f0b38e39 jim-p
$class = "success";
58 2f65de89 jim-p
59 12e3e735 jim-p
if (isset($_REQUEST['userid']) && is_numericint($_REQUEST['userid'])) {
60 4611e283 Steve Beaver
	$userid = $_REQUEST['userid'];
61 56b1ed39 Phil Davis
}
62 e41ec584 Renato Botelho
63
if (isset($userid)) {
64 ad9b5c67 jim-p
	$cert_methods["existing"] = gettext("Choose an existing certificate");
65 c6c398c6 jim-p
	init_config_arr(array('system', 'user'));
66 ad9b5c67 jim-p
	$a_user =& $config['system']['user'];
67
}
68
69 46bd32bb Steve Beaver
init_config_arr(array('ca'));
70
$a_ca = &$config['ca'];
71
72
init_config_arr(array('cert'));
73
$a_cert = &$config['cert'];
74
75 64cc39d3 Matthew Grooms
$internal_ca_count = 0;
76 56b1ed39 Phil Davis
foreach ($a_ca as $ca) {
77
	if ($ca['prv']) {
78 64cc39d3 Matthew Grooms
		$internal_ca_count++;
79 56b1ed39 Phil Davis
	}
80
}
81 64cc39d3 Matthew Grooms
82 96773352 jim-p
if ($_REQUEST['exportp12']) {
83
	$act = 'p12';
84
} elseif ($_REQUEST['exportpkey']) {
85
	$act = 'key';
86
} else {
87
	$act = $_REQUEST['act'];
88
}
89
90
if ($act == 'edit') {
91
	$cert_methods = array(
92
		'edit' => gettext("Edit an existing certificate")
93
	);
94
}
95 8b35eae5 Stephen Beaver
96 f0b38e39 jim-p
if (isset($_REQUEST['id']) && ctype_alnum($_REQUEST['id'])) {
97
	$id = $_REQUEST['id'];
98
}
99
if (!empty($id)) {
100
	$thiscert =& lookup_cert($id);
101
}
102
103 7e83055a jim-p
/* Actions other than 'new' require an ID.
104
 * 'del' action must be submitted via POST. */
105
if ((!empty($act) &&
106
    ($act != 'new') &&
107 f0b38e39 jim-p
    !$thiscert) ||
108 7e83055a jim-p
    (($act == 'del') && empty($_POST))) {
109 2f51259b jim-p
	pfSenseHeader("system_certmanager.php");
110
	exit;
111 64cc39d3 Matthew Grooms
}
112
113 7e83055a jim-p
switch ($act) {
114
	case 'del':
115 f0b38e39 jim-p
		$name = htmlspecialchars($thiscert['descr']);
116
		if (cert_in_use($id)) {
117
			$savemsg = sprintf(gettext("Certificate %s is in use and cannot be deleted"), $name);
118
			$class = "danger";
119
		} else {
120
			foreach ($a_cert as $cid => $acrt) {
121
				if ($acrt['refid'] == $thiscert['refid']) {
122
					unset($a_cert[$cid]);
123
				}
124
			}
125
			$savemsg = sprintf(gettext("Deleted certificate %s"), $name);
126
			write_config($savemsg);
127
		}
128
		unset($act);
129
		break;
130 7e83055a jim-p
	case 'new':
131
		/* New certificate, so set default values */
132
		$pconfig['method'] = $_POST['method'];
133
		$pconfig['keytype'] = "RSA";
134
		$pconfig['keylen'] = "2048";
135 c3cda38e jim-p
		$pconfig['ecname'] = "prime256v1";
136 7e83055a jim-p
		$pconfig['digest_alg'] = "sha256";
137
		$pconfig['csr_keytype'] = "RSA";
138
		$pconfig['csr_keylen'] = "2048";
139 c3cda38e jim-p
		$pconfig['csr_ecname'] = "prime256v1";
140 7e83055a jim-p
		$pconfig['csr_digest_alg'] = "sha256";
141
		$pconfig['csrsign_digest_alg'] = "sha256";
142
		$pconfig['type'] = "user";
143
		$pconfig['lifetime'] = $default_lifetime;
144
		break;
145 96773352 jim-p
	case 'edit':
146
		/* Editing a certificate, so populate values */
147
		$pconfig['descr'] = $thiscert['descr'];
148
		$pconfig['cert'] = base64_decode($thiscert['crt']);
149
		$pconfig['key'] = base64_decode($thiscert['prv']);
150
		break;
151 7e83055a jim-p
	case 'csr':
152
		/* Editing a CSR, so populate values */
153 f0b38e39 jim-p
		$pconfig['descr'] = $thiscert['descr'];
154
		$pconfig['csr'] = base64_decode($thiscert['csr']);
155 7e83055a jim-p
		break;
156
	case 'exp':
157
		/* Exporting a certificate */
158 f0b38e39 jim-p
		send_user_download('data', base64_decode($thiscert['crt']), "{$thiscert['descr']}.crt");
159 7e83055a jim-p
		break;
160
	case 'req':
161
		/* Exporting a certificate signing request */
162 f0b38e39 jim-p
		send_user_download('data', base64_decode($thiscert['csr']), "{$thiscert['descr']}.req");
163 7e83055a jim-p
		break;
164
	case 'key':
165
		/* Exporting a private key */
166 96773352 jim-p
		$keyout = base64_decode($thiscert['prv']);
167
		if (isset($_POST['exportpass']) && !empty($_POST['exportpass'])) {
168 6b44352b Viktor Gurov
			if ((strlen($_POST['exportpass']) < 4) or (strlen($_POST['exportpass']) > 1023)) {
169
				$savemsg = gettext("Export password must be in 4 to 1023 characters.");
170 96773352 jim-p
				$class = 'danger';
171 6b44352b Viktor Gurov
				break;
172
			} else {
173
				$res_key = openssl_pkey_get_private($keyout);
174
				if ($res_key) {
175 8e4ad4c8 Viktor Gurov
					$args = array('encrypt_key_cipher' => OPENSSL_CIPHER_AES_256_CBC);
176
					openssl_pkey_export($res_key, $keyout, $_POST['exportpass'], $args);
177 6b44352b Viktor Gurov
				} else {
178
					$savemsg = gettext("Unable to export password-protected private key.");
179
					$class = 'danger';
180
				}
181 96773352 jim-p
			}
182
		}
183
		if (!empty($keyout)) {
184
			send_user_download('data', $keyout, "{$thiscert['descr']}.key");
185
		}
186 7e83055a jim-p
		break;
187
	case 'p12':
188
		/* Exporting a PKCS#12 file containing the certificate, key, and (if present) CA */
189 28631275 Viktor Gurov
		if (isset($_POST['exportpass']) && !empty($_POST['exportpass'])) {
190 6b44352b Viktor Gurov
			if ((strlen($_POST['exportpass']) < 4) or (strlen($_POST['exportpass']) > 1023)) {
191
				$savemsg = gettext("Export password must be in 4 to 1023 characters.");
192
				$class = 'danger';
193
				break;
194
			} else {
195
				$password = $_POST['exportpass'];
196
			}
197
		} else {
198
			$password = null;
199
		}
200 a7e50981 jim-p
		if (isset($_POST['p12encryption']) &&
201
		    array_key_exists($_POST['p12encryption'], $p12_encryption_levels)) {
202
			$encryption = $_POST['p12encryption'];
203
		} else {
204
			$encryption = 'high';
205
		}
206
		cert_pkcs12_export($thiscert, $encryption, $password, true, 'download');
207 7e83055a jim-p
		break;
208
	default:
209
		break;
210 64cc39d3 Matthew Grooms
}
211
212 7e83055a jim-p
if ($_POST['save'] == gettext("Save")) {
213
	/* Creating a new entry */
214
	$input_errors = array();
215
	$pconfig = $_POST;
216 0edcccc3 Daniel Seebald
217 7e83055a jim-p
	switch ($pconfig['method']) {
218
		case 'sign':
219 2052d3e2 Steve Beaver
			$reqdfields = explode(" ",
220
				"descr catosignwith");
221
			$reqdfieldsn = array(
222
				gettext("Descriptive name"),
223
				gettext("CA to sign with"));
224
225 7db12011 jim-p
			if (($_POST['csrtosign'] === "new") &&
226
			    ((!strstr($_POST['csrpaste'], "BEGIN CERTIFICATE REQUEST") || !strstr($_POST['csrpaste'], "END CERTIFICATE REQUEST")) &&
227
			    (!strstr($_POST['csrpaste'], "BEGIN NEW CERTIFICATE REQUEST") || !strstr($_POST['csrpaste'], "END NEW CERTIFICATE REQUEST")))) {
228 2052d3e2 Steve Beaver
				$input_errors[] = gettext("This signing request does not appear to be valid.");
229
			}
230 55047259 Steve Beaver
231 c8014348 Christian McDonald
			if ( (($_POST['csrtosign'] === "new") && (strlen($_POST['keypaste']) > 0)) &&
232
			    ((!strstr($_POST['keypaste'], "BEGIN PRIVATE KEY") && !strstr($_POST['keypaste'], "BEGIN EC PRIVATE KEY")) ||
233 b1370c94 Viktor Gurov
			    (strstr($_POST['keypaste'], "BEGIN PRIVATE KEY") && !strstr($_POST['keypaste'], "END PRIVATE KEY")) ||
234
			    (strstr($_POST['keypaste'], "BEGIN EC PRIVATE KEY") && !strstr($_POST['keypaste'], "END EC PRIVATE KEY")))) {
235 55047259 Steve Beaver
				$input_errors[] = gettext("This private does not appear to be valid.");
236
				$input_errors[] = gettext("Key data field should be blank, or a valid x509 private key");
237
			}
238 96d78012 Viktor Gurov
239 3a877e4a jim-p
			if ($_POST['lifetime'] > $max_lifetime) {
240
				$input_errors[] = gettext("Lifetime is longer than the maximum allowed value. Use a shorter lifetime.");
241
			}
242 7e83055a jim-p
			break;
243 96773352 jim-p
		case 'edit':
244 7e83055a jim-p
		case 'import':
245 2fe0e0fa jim-p
			/* Make sure we do not have invalid characters in the fields for the certificate */
246
			if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
247
				$input_errors[] = gettext("The field 'Descriptive Name' contains invalid characters.");
248
			}
249 96d78012 Viktor Gurov
			$pkcs12_data = '';
250
			if ($_POST['import_type'] == 'x509') {
251
				$reqdfields = explode(" ",
252
					"descr cert");
253
				$reqdfieldsn = array(
254
					gettext("Descriptive name"),
255
					gettext("Certificate data"));
256
				if ($_POST['cert'] && (!strstr($_POST['cert'], "BEGIN CERTIFICATE") || !strstr($_POST['cert'], "END CERTIFICATE"))) {
257
					$input_errors[] = gettext("This certificate does not appear to be valid.");
258
				}
259 55047259 Steve Beaver
260 96d78012 Viktor Gurov
				if ($_POST['key'] && (cert_get_publickey($_POST['cert'], false) != cert_get_publickey($_POST['key'], false, 'prv'))) {
261
					$input_errors[] = gettext("The submitted private key does not match the submitted certificate data.");
262
				}
263
			} else {
264
				$reqdfields = array('descr');
265
				$reqdfieldsn = array(gettext("Descriptive name"));
266
				if (!empty($_FILES['pkcs12_cert']) && is_uploaded_file($_FILES['pkcs12_cert']['tmp_name'])) {
267
					$pkcs12_file = file_get_contents($_FILES['pkcs12_cert']['tmp_name']);
268
					if (!openssl_pkcs12_read($pkcs12_file, $pkcs12_data, $_POST['pkcs12_pass'])) {
269 392133c7 jim-p
						$input_errors[] = gettext("The submitted password does not unlock the submitted PKCS #12 certificate or the bundle uses unsupported encryption ciphers.");
270 96d78012 Viktor Gurov
					}
271
				} else {
272
					$input_errors[] = gettext("A PKCS #12 certificate store was not uploaded.");
273
				}
274 2cf5db21 jim-p
			}
275 7e83055a jim-p
			break;
276
		case 'internal':
277 64cc39d3 Matthew Grooms
			$reqdfields = explode(" ",
278 ff5bc49c Viktor Gurov
				"descr caref keylen ecname keytype type lifetime dn_commonname");
279 38fb1109 Vinicius Coque
			$reqdfieldsn = array(
280 56b1ed39 Phil Davis
				gettext("Descriptive name"),
281
				gettext("Certificate authority"),
282
				gettext("Key length"),
283 e0f8d364 Viktor Gurov
				gettext("Elliptic Curve Name"),
284 47c46bbd Viktor Gurov
				gettext("Key type"),
285 56b1ed39 Phil Davis
				gettext("Certificate Type"),
286
				gettext("Lifetime"),
287 0c51971b jim-p
				gettext("Common Name"));
288 3a877e4a jim-p
			if ($_POST['lifetime'] > $max_lifetime) {
289
				$input_errors[] = gettext("Lifetime is longer than the maximum allowed value. Use a shorter lifetime.");
290
			}
291 7e83055a jim-p
			break;
292
		case 'external':
293 64cc39d3 Matthew Grooms
			$reqdfields = explode(" ",
294 e0f8d364 Viktor Gurov
				"descr csr_keylen csr_ecname csr_keytype csr_dn_commonname");
295 38fb1109 Vinicius Coque
			$reqdfieldsn = array(
296 56b1ed39 Phil Davis
				gettext("Descriptive name"),
297
				gettext("Key length"),
298 e0f8d364 Viktor Gurov
				gettext("Elliptic Curve Name"),
299 dace81a7 Viktor Gurov
				gettext("Key type"),
300 0c51971b jim-p
				gettext("Common Name"));
301 7e83055a jim-p
			break;
302
		case 'existing':
303 ad9b5c67 jim-p
			$reqdfields = array("certref");
304
			$reqdfieldsn = array(gettext("Existing Certificate Choice"));
305 7e83055a jim-p
			break;
306
		default:
307
			break;
308
	}
309 bf9d50e8 Stephen Beaver
310 7e83055a jim-p
	$altnames = array();
311
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
312
313 96773352 jim-p
	if (!in_array($pconfig['method'], array('edit', 'import', 'existing'))) {
314 7e83055a jim-p
		/* subjectAltNames */
315
		$san_typevar = 'altname_type';
316
		$san_valuevar = 'altname_value';
317
		// This is just the blank alternate name that is added for display purposes. We don't want to validate/save it
318
		if ($_POST["{$san_valuevar}0"] == "") {
319
			unset($_POST["{$san_typevar}0"]);
320
			unset($_POST["{$san_valuevar}0"]);
321
		}
322
		foreach ($_POST as $key => $value) {
323
			$entry = '';
324
			if (!substr_compare($san_typevar, $key, 0, strlen($san_typevar))) {
325
				$entry = substr($key, strlen($san_typevar));
326
				$field = 'type';
327
			} elseif (!substr_compare($san_valuevar, $key, 0, strlen($san_valuevar))) {
328
				$entry = substr($key, strlen($san_valuevar));
329
				$field = 'value';
330 2f65de89 jim-p
			}
331 bf9d50e8 Stephen Beaver
332 28e2b611 jim-p
			if (ctype_digit(strval($entry))) {
333 7e83055a jim-p
				$entry++;	// Pre-bootstrap code is one-indexed, but the bootstrap code is 0-indexed
334
				$altnames[$entry][$field] = $value;
335 2f65de89 jim-p
			}
336 7e83055a jim-p
		}
337 2f65de89 jim-p
338 7e83055a jim-p
		$pconfig['altnames']['item'] = $altnames;
339 b741d2ef jim-p
340 7e83055a jim-p
		/* Input validation for subjectAltNames */
341 bfa5cfef jim-p
		foreach ($altnames as $idx => $altname) {
342
			/* Skip SAN entries with empty values
343
			 * https://redmine.pfsense.org/issues/14183
344
			 */
345
			if (empty($altname['value'])) {
346
				unset($altnames[$idx]);
347
				continue;
348
			}
349 7e83055a jim-p
			switch ($altname['type']) {
350
				case "DNS":
351
					if (!is_hostname($altname['value'], true) || is_ipaddr($altname['value'])) {
352
						$input_errors[] = gettext("DNS subjectAltName values must be valid hostnames, FQDNs or wildcard domains.");
353 ed76624b jim-p
					}
354
					break;
355 7e83055a jim-p
				case "IP":
356
					if (!is_ipaddr($altname['value'])) {
357
						$input_errors[] = gettext("IP subjectAltName values must be valid IP Addresses");
358 dace81a7 Viktor Gurov
					}
359 7e83055a jim-p
					break;
360
				case "email":
361
					if (empty($altname['value'])) {
362
						$input_errors[] = gettext("An e-mail address must be provided for this type of subjectAltName");
363 dace81a7 Viktor Gurov
					}
364 7e83055a jim-p
					if (preg_match("/[\!\#\$\%\^\(\)\~\?\>\<\&\/\\\,\"\']/", $altname['value'])) {
365
						$input_errors[] = gettext("The e-mail provided in a subjectAltName contains invalid characters.");
366 ed76624b jim-p
					}
367
					break;
368 7e83055a jim-p
				case "URI":
369
					/* Close enough? */
370
					if (!is_URL($altname['value'])) {
371
						$input_errors[] = gettext("URI subjectAltName types must be a valid URI");
372 ed76624b jim-p
					}
373
					break;
374
				default:
375 7e83055a jim-p
					$input_errors[] = gettext("Unrecognized subjectAltName type.");
376 aec3a259 jim-p
			}
377 547c56c4 jim-p
		}
378 64cc39d3 Matthew Grooms
379 7e83055a jim-p
		/* Make sure we do not have invalid characters in the fields for the certificate */
380
		if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
381
			$input_errors[] = gettext("The field 'Descriptive Name' contains invalid characters.");
382
		}
383 fe31d06f Viktor G
		$pattern = '/[^a-zA-Z0-9\ \'\/~`\!@#\$%\^&\*\(\)_\-\+=\{\}\[\]\|;:"\<\>,\.\?\\\]/';
384
		if (!empty($_POST['dn_commonname']) && preg_match($pattern, $_POST['dn_commonname'])) {
385
			$input_errors[] = gettext("The field 'Common Name' contains invalid characters.");
386
		}
387
		if (!empty($_POST['dn_state']) && preg_match($pattern, $_POST['dn_state'])) {
388
			$input_errors[] = gettext("The field 'State or Province' contains invalid characters.");
389
		}
390
		if (!empty($_POST['dn_city']) && preg_match($pattern, $_POST['dn_city'])) {
391
			$input_errors[] = gettext("The field 'City' contains invalid characters.");
392
		}
393
		if (!empty($_POST['dn_organization']) && preg_match($pattern, $_POST['dn_organization'])) {
394
			$input_errors[] = gettext("The field 'Organization' contains invalid characters.");
395
		}
396
		if (!empty($_POST['dn_organizationalunit']) && preg_match($pattern, $_POST['dn_organizationalunit'])) {
397
			$input_errors[] = gettext("The field 'Organizational Unit' contains invalid characters.");
398
		}
399 64cc39d3 Matthew Grooms
400 7e83055a jim-p
		switch ($pconfig['method']) {
401
			case "internal":
402
				if (isset($_POST["keytype"]) && !in_array($_POST["keytype"], $cert_keytypes)) {
403
					$input_errors[] = gettext("Please select a valid Key Type.");
404 56b1ed39 Phil Davis
				}
405 7e83055a jim-p
				if (isset($_POST["keylen"]) && !in_array($_POST["keylen"], $cert_keylens)) {
406
					$input_errors[] = gettext("Please select a valid Key Length.");
407 2052d3e2 Steve Beaver
				}
408 cffcf9bf jim-p
				if (isset($_POST["ecname"]) && !in_array($_POST["ecname"], array_keys($openssl_ecnames))) {
409 7e83055a jim-p
					$input_errors[] = gettext("Please select a valid Elliptic Curve Name.");
410
				}
411
				if (!in_array($_POST["digest_alg"], $openssl_digest_algs)) {
412
					$input_errors[] = gettext("Please select a valid Digest Algorithm.");
413
				}
414
				break;
415
			case "external":
416
				if (isset($_POST["csr_keytype"]) && !in_array($_POST["csr_keytype"], $cert_keytypes)) {
417
					$input_errors[] = gettext("Please select a valid Key Type.");
418 55047259 Steve Beaver
				}
419 7e83055a jim-p
				if (isset($_POST["csr_keylen"]) && !in_array($_POST["csr_keylen"], $cert_keylens)) {
420
					$input_errors[] = gettext("Please select a valid Key Length.");
421
				}
422 cffcf9bf jim-p
				if (isset($_POST["csr_ecname"]) && !in_array($_POST["csr_ecname"], array_keys($openssl_ecnames))) {
423 7e83055a jim-p
					$input_errors[] = gettext("Please select a valid Elliptic Curve Name.");
424
				}
425
				if (!in_array($_POST["csr_digest_alg"], $openssl_digest_algs)) {
426
					$input_errors[] = gettext("Please select a valid Digest Algorithm.");
427
				}
428
				break;
429
			case "sign":
430
				if (!in_array($_POST["csrsign_digest_alg"], $openssl_digest_algs)) {
431
					$input_errors[] = gettext("Please select a valid Digest Algorithm.");
432
				}
433
				break;
434
			default:
435
				break;
436
		}
437
	}
438 2052d3e2 Steve Beaver
439 7e83055a jim-p
	/* save modifications */
440
	if (!$input_errors) {
441 96773352 jim-p
		$old_err_level = error_reporting(0); /* otherwise openssl_ functions throw warnings directly to a page breaking menu tabs */
442 b078cd59 Steve Beaver
443 96773352 jim-p
		if (isset($id) && $thiscert) {
444
			$cert = $thiscert;
445 7e83055a jim-p
		} else {
446
			$cert = array();
447
			$cert['refid'] = uniqid();
448 96773352 jim-p
		}
449 ad9b5c67 jim-p
450 96773352 jim-p
		$cert['descr'] = $pconfig['descr'];
451 282b6c66 jim-p
452 96773352 jim-p
		switch($pconfig['method']) {
453
			case 'existing':
454
				/* Add an existing certificate to a user */
455
				$ucert = lookup_cert($pconfig['certref']);
456
				if ($ucert && $a_user) {
457
					$a_user[$userid]['cert'][] = $ucert['refid'];
458 2fe0e0fa jim-p
					$savemsg = sprintf(gettext("Added certificate %s to user %s"), htmlspecialchars($ucert['descr']), $a_user[$userid]['name']);
459 96773352 jim-p
				}
460
				unset($cert);
461
				break;
462
			case 'sign':
463
				/* Sign a CSR */
464
				$csrid = lookup_cert($pconfig['csrtosign']);
465
				$ca = & lookup_ca($pconfig['catosignwith']);
466
				// Read the CSR from $config, or if a new one, from the textarea
467
				if ($pconfig['csrtosign'] === "new") {
468
					$csr = $pconfig['csrpaste'];
469
				} else {
470
					$csr = base64_decode($csrid['csr']);
471
				}
472
				if (count($altnames)) {
473
					foreach ($altnames as $altname) {
474 692510f2 Viktor G
						$altnames_tmp[] = "{$altname['type']}:" . $altname['value'];
475 96773352 jim-p
					}
476
					$altname_str = implode(",", $altnames_tmp);
477
				}
478
				$n509 = csr_sign($csr, $ca, $pconfig['csrsign_lifetime'], $pconfig['type'], $altname_str, $pconfig['csrsign_digest_alg']);
479
				if ($n509) {
480
					// Gather the details required to save the new cert
481
					$newcert = array();
482
					$newcert['refid'] = uniqid();
483
					$newcert['caref'] = $pconfig['catosignwith'];
484
					$newcert['descr'] = $pconfig['descr'];
485
					$newcert['type'] = $pconfig['type'];
486
					$newcert['crt'] = base64_encode($n509);
487
					if ($pconfig['csrtosign'] === "new") {
488
						$newcert['prv'] = base64_encode($pconfig['keypaste']);
489
					} else {
490
						$newcert['prv'] = $csrid['prv'];
491
					}
492
					// Add it to the config file
493
					$config['cert'][] = $newcert;
494 2fe0e0fa jim-p
					$savemsg = sprintf(gettext("Signed certificate %s"), htmlspecialchars($newcert['descr']));
495
					unset($act);
496 96773352 jim-p
				}
497
				unset($cert);
498
				break;
499
			case 'edit':
500
				cert_import($cert, $pconfig['cert'], $pconfig['key']);
501 2fe0e0fa jim-p
				$savemsg = sprintf(gettext("Edited certificate %s"), htmlspecialchars($cert['descr']));
502
				unset($act);
503 96773352 jim-p
				break;
504
			case 'import':
505
				/* Import an external certificate+key */
506 96d78012 Viktor Gurov
				if ($pkcs12_data) {
507
					$pconfig['cert'] = $pkcs12_data['cert'];
508
					$pconfig['key'] = $pkcs12_data['pkey'];
509
					if ($_POST['pkcs12_intermediate'] && is_array($pkcs12_data['extracerts'])) {
510
						foreach ($pkcs12_data['extracerts'] as $intermediate) {
511
							$int_data = openssl_x509_parse($intermediate);
512
							if (!$int_data) continue;
513
							$cn = $int_data['subject']['CN'];
514
							$int_ca = array('descr' => $cn, 'refid' => uniqid());
515
							if (ca_import($int_ca, $intermediate)) {
516
								$a_ca[] = $int_ca;
517
							}
518
						}
519
					}
520
				}
521 7e83055a jim-p
				cert_import($cert, $pconfig['cert'], $pconfig['key']);
522 2fe0e0fa jim-p
				$savemsg = sprintf(gettext("Imported certificate %s"), htmlspecialchars($cert['descr']));
523
				unset($act);
524 96773352 jim-p
				break;
525
			case 'internal':
526
				/* Create an internal certificate */
527 692510f2 Viktor G
				$dn = array('commonName' => $pconfig['dn_commonname']);
528 7e83055a jim-p
				if (!empty($pconfig['dn_country'])) {
529
					$dn['countryName'] = $pconfig['dn_country'];
530
				}
531
				if (!empty($pconfig['dn_state'])) {
532 692510f2 Viktor G
					$dn['stateOrProvinceName'] = $pconfig['dn_state'];
533 7e83055a jim-p
				}
534
				if (!empty($pconfig['dn_city'])) {
535 692510f2 Viktor G
					$dn['localityName'] = $pconfig['dn_city'];
536 7e83055a jim-p
				}
537
				if (!empty($pconfig['dn_organization'])) {
538 692510f2 Viktor G
					$dn['organizationName'] = $pconfig['dn_organization'];
539 7e83055a jim-p
				}
540
				if (!empty($pconfig['dn_organizationalunit'])) {
541 692510f2 Viktor G
					$dn['organizationalUnitName'] = $pconfig['dn_organizationalunit'];
542 7e83055a jim-p
				}
543
				$altnames_tmp = array();
544
				$cn_altname = cert_add_altname_type($pconfig['dn_commonname']);
545
				if (!empty($cn_altname)) {
546
					$altnames_tmp[] = $cn_altname;
547
				}
548
				if (count($altnames)) {
549
					foreach ($altnames as $altname) {
550
						// The CN is added as a SAN automatically, do not add it again.
551
						if ($altname['value'] != $pconfig['dn_commonname']) {
552 692510f2 Viktor G
							$altnames_tmp[] = "{$altname['type']}:" . $altname['value'];
553 2f65de89 jim-p
						}
554 282b6c66 jim-p
					}
555 7e83055a jim-p
				}
556
				if (!empty($altnames_tmp)) {
557
					$dn['subjectAltName'] = implode(",", $altnames_tmp);
558
				}
559
				if (!cert_create($cert, $pconfig['caref'], $pconfig['keylen'], $pconfig['lifetime'], $dn, $pconfig['type'], $pconfig['digest_alg'], $pconfig['keytype'], $pconfig['ecname'])) {
560
					$input_errors = array();
561
					while ($ssl_err = openssl_error_string()) {
562
						if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
563
							$input_errors[] = sprintf(gettext("OpenSSL Library Error: %s"), $ssl_err);
564 22b380aa Evgeny Yurchenko
						}
565
					}
566 ad9b5c67 jim-p
				}
567 2fe0e0fa jim-p
				$savemsg = sprintf(gettext("Created internal certificate %s"), htmlspecialchars($cert['descr']));
568
				unset($act);
569 96773352 jim-p
				break;
570
			case 'external':
571
				/* Create a certificate signing request */
572 692510f2 Viktor G
				$dn = array('commonName' => $pconfig['csr_dn_commonname']);
573 7e83055a jim-p
				if (!empty($pconfig['csr_dn_country'])) {
574
					$dn['countryName'] = $pconfig['csr_dn_country'];
575
				}
576
				if (!empty($pconfig['csr_dn_state'])) {
577 692510f2 Viktor G
					$dn['stateOrProvinceName'] = $pconfig['csr_dn_state'];
578 7e83055a jim-p
				}
579
				if (!empty($pconfig['csr_dn_city'])) {
580 692510f2 Viktor G
					$dn['localityName'] = $pconfig['csr_dn_city'];
581 7e83055a jim-p
				}
582
				if (!empty($pconfig['csr_dn_organization'])) {
583 692510f2 Viktor G
					$dn['organizationName'] = $pconfig['csr_dn_organization'];
584 7e83055a jim-p
				}
585
				if (!empty($pconfig['csr_dn_organizationalunit'])) {
586 692510f2 Viktor G
					$dn['organizationalUnitName'] = $pconfig['csr_dn_organizationalunit'];
587 7e83055a jim-p
				}
588
				$altnames_tmp = array();
589
				$cn_altname = cert_add_altname_type($pconfig['csr_dn_commonname']);
590
				if (!empty($cn_altname)) {
591
					$altnames_tmp[] = $cn_altname;
592
				}
593
				if (count($altnames)) {
594
					foreach ($altnames as $altname) {
595
						// The CN is added as a SAN automatically, do not add it again.
596
						if ($altname['value'] != $pconfig['csr_dn_commonname']) {
597 692510f2 Viktor G
							$altnames_tmp[] = "{$altname['type']}:" . $altname['value'];
598 7e83055a jim-p
						}
599
					}
600
				}
601
				if (!empty($altnames_tmp)) {
602
					$dn['subjectAltName'] = implode(",", $altnames_tmp);
603 56b1ed39 Phil Davis
				}
604 7e83055a jim-p
				if (!csr_generate($cert, $pconfig['csr_keylen'], $dn, $pconfig['type'], $pconfig['csr_digest_alg'], $pconfig['csr_keytype'], $pconfig['csr_ecname'])) {
605
					$input_errors = array();
606
					while ($ssl_err = openssl_error_string()) {
607
						if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
608
							$input_errors[] = sprintf(gettext("OpenSSL Library Error: %s"), $ssl_err);
609
						}
610
					}
611 56b1ed39 Phil Davis
				}
612 2fe0e0fa jim-p
				$savemsg = sprintf(gettext("Created certificate signing request %s"), htmlspecialchars($cert['descr']));
613
				unset($act);
614 96773352 jim-p
				break;
615
			default:
616
				break;
617
		}
618
		error_reporting($old_err_level);
619 7e83055a jim-p
620 96773352 jim-p
		if (isset($id) && $thiscert) {
621
			$thiscert = $cert;
622
		} elseif ($cert) {
623
			$a_cert[] = $cert;
624
		}
625 64cc39d3 Matthew Grooms
626 96773352 jim-p
		if (isset($a_user) && isset($userid)) {
627
			$a_user[$userid]['cert'][] = $cert['refid'];
628 64cc39d3 Matthew Grooms
		}
629
630 7e83055a jim-p
		if (!$input_errors) {
631 f0b38e39 jim-p
			write_config($savemsg);
632 b741d2ef jim-p
		}
633
634 7e83055a jim-p
		if ((isset($userid) && is_numeric($userid)) && !$input_errors) {
635
			post_redirect("system_usermanager.php", array('act' => 'edit', 'userid' => $userid));
636
			exit;
637 a828210b yakatz
		}
638 7e83055a jim-p
	}
639
} elseif ($_POST['save'] == gettext("Update")) {
640
	/* Updating a certificate signing request */
641
	unset($input_errors);
642
	$pconfig = $_POST;
643 64cc39d3 Matthew Grooms
644 7e83055a jim-p
	/* input validation */
645
	$reqdfields = explode(" ", "descr cert");
646
	$reqdfieldsn = array(
647
		gettext("Descriptive name"),
648
		gettext("Final Certificate data"));
649 64cc39d3 Matthew Grooms
650 7e83055a jim-p
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
651 64cc39d3 Matthew Grooms
652 7e83055a jim-p
	if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
653
		$input_errors[] = gettext("The field 'Descriptive Name' contains invalid characters.");
654
	}
655 64cc39d3 Matthew Grooms
656 7e83055a jim-p
	$mod_csr = cert_get_publickey($pconfig['csr'], false, 'csr');
657
	$mod_cert = cert_get_publickey($pconfig['cert'], false);
658 64cc39d3 Matthew Grooms
659 7e83055a jim-p
	if (strcmp($mod_csr, $mod_cert)) {
660
		// simply: if the moduli don't match, then the private key and public key won't match
661
		$input_errors[] = gettext("The certificate public key does not match the signing request public key.");
662
		$subject_mismatch = true;
663
	}
664 64cc39d3 Matthew Grooms
665 7e83055a jim-p
	/* save modifications */
666
	if (!$input_errors) {
667 f0b38e39 jim-p
		$cert = $thiscert;
668 7e83055a jim-p
		$cert['descr'] = $pconfig['descr'];
669
		csr_complete($cert, $pconfig['cert']);
670 f0b38e39 jim-p
		$thiscert = $cert;
671 2fe0e0fa jim-p
		$savemsg = sprintf(gettext("Updated certificate signing request %s"), htmlspecialchars($pconfig['descr']));
672 f0b38e39 jim-p
		write_config($savemsg);
673 7e83055a jim-p
		pfSenseHeader("system_certmanager.php");
674 64cc39d3 Matthew Grooms
	}
675
}
676
677 c8014348 Christian McDonald
$pgtitle = array(gettext('System'), gettext('Certificates'), gettext('Certificates'));
678 edcd7535 Phil Davis
$pglinks = array("", "system_camanager.php", "system_certmanager.php");
679 56c6b1cb k-paulius
680 7e83055a jim-p
if (($act == "new" || ($_POST['save'] == gettext("Save") && $input_errors)) ||
681
    ($act == "csr" || ($_POST['save'] == gettext("Update") && $input_errors))) {
682 56c6b1cb k-paulius
	$pgtitle[] = gettext('Edit');
683 edcd7535 Phil Davis
	$pglinks[] = "@self";
684 56c6b1cb k-paulius
}
685 64cc39d3 Matthew Grooms
include("head.inc");
686 b49f31d0 Sjon Hortensius
687 78863416 Phil Davis
if ($input_errors) {
688 b49f31d0 Sjon Hortensius
	print_input_errors($input_errors);
689 78863416 Phil Davis
}
690 0edcccc3 Daniel Seebald
691 78863416 Phil Davis
if ($savemsg) {
692 f0b38e39 jim-p
	print_info_box($savemsg, $class);
693 78863416 Phil Davis
}
694 b49f31d0 Sjon Hortensius
695
$tab_array = array();
696 c8014348 Christian McDonald
$tab_array[] = array(gettext('Authorities'), false, 'system_camanager.php');
697
$tab_array[] = array(gettext('Certificates'), true, 'system_certmanager.php');
698
$tab_array[] = array(gettext('Certificate Revocation'), false, 'system_crlmanager.php');
699 b49f31d0 Sjon Hortensius
display_top_tabs($tab_array);
700
701 96773352 jim-p
if (in_array($act, array('new', 'edit')) || (($_POST['save'] == gettext("Save")) && $input_errors)) {
702 b35250d9 NewEraCracker
	$form = new Form();
703 96d78012 Viktor Gurov
	$form->setAction('system_certmanager.php')->setMultipartEncoding();
704 b49f31d0 Sjon Hortensius
705 b35250d9 NewEraCracker
	if (isset($userid) && $a_user) {
706
		$form->addGlobal(new Form_Input(
707
			'userid',
708
			null,
709
			'hidden',
710
			$userid
711
		));
712
	}
713 b49f31d0 Sjon Hortensius
714 f0b38e39 jim-p
	if (isset($id) && $thiscert) {
715 b49f31d0 Sjon Hortensius
		$form->addGlobal(new Form_Input(
716
			'id',
717
			null,
718
			'hidden',
719
			$id
720
		));
721 64cc39d3 Matthew Grooms
	}
722 b49f31d0 Sjon Hortensius
723 2fe0e0fa jim-p
	if ($act) {
724
		$form->addGlobal(new Form_Input(
725
			'act',
726
			null,
727
			'hidden',
728
			$act
729
		));
730
	}
731
732 96773352 jim-p
	switch ($act) {
733
		case 'edit':
734
			$maintitle = gettext('Edit an Existing Certificate');
735
			break;
736
		case 'new':
737
		default:
738
			$maintitle = gettext('Add/Sign a New Certificate');
739
			break;
740
	}
741
742
	$section = new Form_Section($maintitle);
743 b35250d9 NewEraCracker
744 96773352 jim-p
	if (!isset($id) || ($act == 'edit')) {
745 b35250d9 NewEraCracker
		$section->addInput(new Form_Select(
746
			'method',
747 153c3aa6 Phil Davis
			'*Method',
748 b35250d9 NewEraCracker
			$pconfig['method'],
749
			$cert_methods
750
		))->toggles();
751
	}
752
753 b49f31d0 Sjon Hortensius
	$section->addInput(new Form_Input(
754
		'descr',
755 153c3aa6 Phil Davis
		'*Descriptive name',
756 b49f31d0 Sjon Hortensius
		'text',
757 b35250d9 NewEraCracker
		($a_user && empty($pconfig['descr'])) ? $a_user[$userid]['name'] : $pconfig['descr']
758 f16d3f4d jim-p
	))->addClass('toggle-internal toggle-import toggle-edit toggle-external toggle-sign toggle-existing collapse')
759
	->setHelp('The name of this entry as displayed in the GUI for reference.%s' .
760
		'This name can contain spaces but it cannot contain any of the ' .
761
		'following characters: %s', '<br/>', "?, >, <, &, /, \, \", '");
762 96773352 jim-p
763
	if (!empty($pconfig['cert'])) {
764
		$section->addInput(new Form_StaticText(
765
			"Subject",
766
			htmlspecialchars(cert_get_subject($pconfig['cert'], false))
767
		))->addClass('toggle-edit collapse');
768
	}
769 b49f31d0 Sjon Hortensius
770 b35250d9 NewEraCracker
	$form->add($section);
771 2052d3e2 Steve Beaver
772 46bd32bb Steve Beaver
	// Return an array containing the IDs od all CAs
773
	function list_cas() {
774
		global $a_ca;
775
		$allCas = array();
776
777
		foreach ($a_ca as $ca) {
778
			if ($ca['prv']) {
779
				$allCas[$ca['refid']] = $ca['descr'];
780
			}
781
		}
782
783
		return $allCas;
784
	}
785
786
	// Return an array containing the IDs od all CSRs
787
	function list_csrs() {
788
		global $config;
789
		$allCsrs = array();
790
791
		foreach ($config['cert'] as $cert) {
792
			if ($cert['csr']) {
793
				$allCsrs[$cert['refid']] = $cert['descr'];
794
			}
795
		}
796
797
		return ['new' => gettext('New CSR (Paste below)')] + $allCsrs;
798
	}
799
800 2052d3e2 Steve Beaver
	$section = new Form_Section('Sign CSR');
801
	$section->addClass('toggle-sign collapse');
802
803
	$section->AddInput(new Form_Select(
804
		'catosignwith',
805
		'*CA to sign with',
806
		$pconfig['catosignwith'],
807
		list_cas()
808
	));
809
810
	$section->AddInput(new Form_Select(
811
		'csrtosign',
812
		'*CSR to sign',
813
		isset($pconfig['csrtosign']) ? $pconfig['csrtosign'] : 'new',
814
		list_csrs()
815
	));
816
817
	$section->addInput(new Form_Textarea(
818
		'csrpaste',
819
		'CSR data',
820
		$pconfig['csrpaste']
821
	))->setHelp('Paste a Certificate Signing Request in X.509 PEM format here.');
822
823 55047259 Steve Beaver
	$section->addInput(new Form_Textarea(
824
		'keypaste',
825
		'Key data',
826
		$pconfig['keypaste']
827 2568e151 Christian McDonald
	))->setHelp('Optionally paste a private key here. The key will be associated with the newly signed certificate in %1$s', g_get('product_label'));
828 55047259 Steve Beaver
829 0c82b8c2 jim-p
	$section->addInput(new Form_Input(
830
		'csrsign_lifetime',
831
		'*Certificate Lifetime (days)',
832
		'number',
833 3a877e4a jim-p
		$pconfig['csrsign_lifetime'] ? $pconfig['csrsign_lifetime']:$default_lifetime,
834
		['max' => $max_lifetime]
835 3f0b7bc3 jim-p
	))->setHelp('The length of time the signed certificate will be valid, in days. %1$s' .
836 f944f4a7 jim-p
		'Server certificates should not have a lifetime over %2$s days or some platforms ' .
837
		'may consider the certificate invalid.', '<br/>', $cert_strict_values['max_server_cert_lifetime']);
838 aec3a259 jim-p
	$section->addInput(new Form_Select(
839
		'csrsign_digest_alg',
840
		'*Digest Algorithm',
841
		$pconfig['csrsign_digest_alg'],
842
		array_combine($openssl_digest_algs, $openssl_digest_algs)
843 3f0b7bc3 jim-p
	))->setHelp('The digest method used when the certificate is signed. %1$s' .
844 e1267c0f jim-p
		'The best practice is to use SHA256 or higher. '.
845
		'Some services and platforms, such as the GUI web server and OpenVPN, consider weaker digest algorithms invalid.', '<br/>');
846 0c82b8c2 jim-p
847 2052d3e2 Steve Beaver
	$form->add($section);
848
849 96773352 jim-p
	if ($act == 'edit') {
850
		$editimport = gettext("Edit Certificate");
851
	} else {
852
		$editimport = gettext("Import Certificate");
853
	}
854
855
	$section = new Form_Section($editimport);
856
	$section->addClass('toggle-import toggle-edit collapse');
857 b49f31d0 Sjon Hortensius
858 96d78012 Viktor Gurov
	$group = new Form_Group('Certificate Type');
859
860
	$group->add(new Form_Checkbox(
861
		'import_type',
862
		'Certificate Type',
863
		'X.509 (PEM)',
864
		(!isset($pconfig['import_type']) || $pconfig['import_type'] == 'x509'),
865
		'x509'
866
	))->displayAsRadio()->addClass('import_type_toggle');
867
868
	$group->add(new Form_Checkbox(
869
		'import_type',
870
		'Certificate Type',
871
		'PKCS #12 (PFX)',
872
		(isset($pconfig['import_type']) && $pconfig['import_type'] == 'pkcs12'),
873
		'pkcs12'
874
	))->displayAsRadio()->addClass('import_type_toggle');
875
876
	$section->add($group);
877
878 b49f31d0 Sjon Hortensius
	$section->addInput(new Form_Textarea(
879
		'cert',
880 153c3aa6 Phil Davis
		'*Certificate data',
881 78863416 Phil Davis
		$pconfig['cert']
882 b35250d9 NewEraCracker
	))->setHelp('Paste a certificate in X.509 PEM format here.');
883
884
	$section->addInput(new Form_Textarea(
885
		'key',
886 8c145373 Viktor G
		'Private key data',
887 b35250d9 NewEraCracker
		$pconfig['key']
888 8c145373 Viktor G
	))->setHelp('Paste a private key in X.509 PEM format here. This field may remain empty in certain cases, such as when the private key is stored on a PKCS#11 token.');
889 b49f31d0 Sjon Hortensius
890 96d78012 Viktor Gurov
	$section->addInput(new Form_Input(
891
		'pkcs12_cert',
892
		'PKCS #12 certificate',
893
		'file',
894
		$pconfig['pkcs12_cert']
895
	))->setHelp('Select a PKCS #12 certificate store.');
896
897
	$section->addInput(new Form_Input(
898
		'pkcs12_pass',
899
		'PKCS #12 certificate password',
900
		'password',
901
		$pconfig['pkcs12_pass']
902
	))->setHelp('Enter the password to unlock the PKCS #12 certificate store.');
903
904
	$section->addInput(new Form_Checkbox(
905
		'pkcs12_intermediate',
906
		'Intermediates',
907
		'Import intermediate CAs',
908
		isset($pconfig['pkcs12_intermediate'])
909
	))->setHelp('Import any intermediate certificate authorities found in the PKCS #12 certificate store.');
910
911 67b49e4c Viktor G
	if ($act == 'edit') {
912
		$section->addInput(new Form_Input(
913
			'exportpass',
914
			'Export Password',
915
			'password',
916
			null,
917
			['placeholder' => gettext('Export Password'), 'autocomplete' => 'new-password']
918
		))->setHelp('Enter the password to use when using the export buttons below (not stored)')->addClass('toggle-edit collapse');
919 a7e50981 jim-p
		$section->addInput(new Form_Select(
920
		'p12encryption',
921
		'PKCS#12 Encryption',
922
		'high',
923
		$p12_encryption_levels
924
		))->setHelp('Select the level of encryption to use when exporting a PKCS#12 archive. ' .
925
				'Encryption support varies by Operating System and program');
926 67b49e4c Viktor G
	}
927 96773352 jim-p
928 b49f31d0 Sjon Hortensius
	$form->add($section);
929 b35250d9 NewEraCracker
	$section = new Form_Section('Internal Certificate');
930
	$section->addClass('toggle-internal collapse');
931
932
	if (!$internal_ca_count) {
933
		$section->addInput(new Form_StaticText(
934 153c3aa6 Phil Davis
			'*Certificate authority',
935 781d9ce4 Phil Davis
			gettext('No internal Certificate Authorities have been defined. ') .
936
			gettext('An internal CA must be defined in order to create an internal certificate. ') .
937
			sprintf(gettext('%1$sCreate%2$s an internal CA.'), '<a href="system_camanager.php?act=new&amp;method=internal"> ', '</a>')
938 b35250d9 NewEraCracker
		));
939
	} else {
940
		$allCas = array();
941
		foreach ($a_ca as $ca) {
942
			if (!$ca['prv']) {
943
				continue;
944
			}
945 b49f31d0 Sjon Hortensius
946 b35250d9 NewEraCracker
			$allCas[ $ca['refid'] ] = $ca['descr'];
947
		}
948 64cc39d3 Matthew Grooms
949 b35250d9 NewEraCracker
		$section->addInput(new Form_Select(
950
			'caref',
951 153c3aa6 Phil Davis
			'*Certificate authority',
952 b35250d9 NewEraCracker
			$pconfig['caref'],
953
			$allCas
954
		));
955
	}
956 64cc39d3 Matthew Grooms
957 b35250d9 NewEraCracker
	$section->addInput(new Form_Select(
958 47c46bbd Viktor Gurov
		'keytype',
959
		'*Key type',
960
		$pconfig['keytype'],
961
		array_combine($cert_keytypes, $cert_keytypes)
962
	));
963
964 dace81a7 Viktor Gurov
	$group = new Form_Group($i == 0 ? '*Key length':'');
965 e0f8d364 Viktor Gurov
	$group->addClass('rsakeys');
966 dace81a7 Viktor Gurov
	$group->add(new Form_Select(
967 b35250d9 NewEraCracker
		'keylen',
968 dace81a7 Viktor Gurov
		null,
969 b35250d9 NewEraCracker
		$pconfig['keylen'],
970
		array_combine($cert_keylens, $cert_keylens)
971 3f0b7bc3 jim-p
	))->setHelp('The length to use when generating a new RSA key, in bits. %1$s' .
972
		'The Key Length should not be lower than 2048 or some platforms ' .
973
		'may consider the certificate invalid.', '<br/>');
974 dace81a7 Viktor Gurov
	$section->add($group);
975
976 e0f8d364 Viktor Gurov
	$group = new Form_Group($i == 0 ? '*Elliptic Curve Name':'');
977 2d13c7fc Viktor Gurov
	$group->addClass('ecnames');
978 dace81a7 Viktor Gurov
	$group->add(new Form_Select(
979 e0f8d364 Viktor Gurov
		'ecname',
980 dace81a7 Viktor Gurov
		null,
981 e0f8d364 Viktor Gurov
		$pconfig['ecname'],
982 cffcf9bf jim-p
		$openssl_ecnames
983
	))->setHelp('Curves may not be compatible with all uses. Known compatible curve uses are denoted in brackets.');
984 dace81a7 Viktor Gurov
	$section->add($group);
985 64cc39d3 Matthew Grooms
986 b35250d9 NewEraCracker
	$section->addInput(new Form_Select(
987
		'digest_alg',
988 153c3aa6 Phil Davis
		'*Digest Algorithm',
989 b35250d9 NewEraCracker
		$pconfig['digest_alg'],
990
		array_combine($openssl_digest_algs, $openssl_digest_algs)
991 3f0b7bc3 jim-p
	))->setHelp('The digest method used when the certificate is signed. %1$s' .
992 e1267c0f jim-p
		'The best practice is to use SHA256 or higher. '.
993
		'Some services and platforms, such as the GUI web server and OpenVPN, consider weaker digest algorithms invalid.', '<br/>');
994 b49f31d0 Sjon Hortensius
995 b35250d9 NewEraCracker
	$section->addInput(new Form_Input(
996
		'lifetime',
997 153c3aa6 Phil Davis
		'*Lifetime (days)',
998 b35250d9 NewEraCracker
		'number',
999 3a877e4a jim-p
		$pconfig['lifetime'],
1000
		['max' => $max_lifetime]
1001 3f0b7bc3 jim-p
	))->setHelp('The length of time the signed certificate will be valid, in days. %1$s' .
1002 f944f4a7 jim-p
		'Server certificates should not have a lifetime over %2$s days or some platforms ' .
1003
		'may consider the certificate invalid.', '<br/>', $cert_strict_values['max_server_cert_lifetime']);
1004 b49f31d0 Sjon Hortensius
1005 26e3967a jim-p
	$section->addInput(new Form_Input(
1006
		'dn_commonname',
1007
		'*Common Name',
1008
		'text',
1009
		$pconfig['dn_commonname'],
1010
		['placeholder' => 'e.g. www.example.com']
1011
	));
1012
1013
	$section->addInput(new Form_StaticText(
1014
		null,
1015
		gettext('The following certificate subject components are optional and may be left blank.')
1016
	));
1017
1018 b49f31d0 Sjon Hortensius
	$section->addInput(new Form_Select(
1019 b35250d9 NewEraCracker
		'dn_country',
1020 80d50253 jim-p
		'Country Code',
1021 b35250d9 NewEraCracker
		$pconfig['dn_country'],
1022 232b1a69 Renato Botelho
		get_cert_country_codes()
1023 b49f31d0 Sjon Hortensius
	));
1024
1025 b35250d9 NewEraCracker
	$section->addInput(new Form_Input(
1026
		'dn_state',
1027 80d50253 jim-p
		'State or Province',
1028 b35250d9 NewEraCracker
		'text',
1029
		$pconfig['dn_state'],
1030
		['placeholder' => 'e.g. Texas']
1031 b49f31d0 Sjon Hortensius
	));
1032
1033 b35250d9 NewEraCracker
	$section->addInput(new Form_Input(
1034
		'dn_city',
1035 80d50253 jim-p
		'City',
1036 b35250d9 NewEraCracker
		'text',
1037
		$pconfig['dn_city'],
1038
		['placeholder' => 'e.g. Austin']
1039
	));
1040
1041
	$section->addInput(new Form_Input(
1042
		'dn_organization',
1043 80d50253 jim-p
		'Organization',
1044 b35250d9 NewEraCracker
		'text',
1045
		$pconfig['dn_organization'],
1046 da0f70ed jim-p
		['placeholder' => 'e.g. My Company Inc']
1047
	));
1048
1049
	$section->addInput(new Form_Input(
1050
		'dn_organizationalunit',
1051
		'Organizational Unit',
1052
		'text',
1053
		$pconfig['dn_organizationalunit'],
1054
		['placeholder' => 'e.g. My Department Name (optional)']
1055 b35250d9 NewEraCracker
	));
1056
1057
	$form->add($section);
1058
	$section = new Form_Section('External Signing Request');
1059
	$section->addClass('toggle-external collapse');
1060
1061 b49f31d0 Sjon Hortensius
	$section->addInput(new Form_Select(
1062 47c46bbd Viktor Gurov
		'csr_keytype',
1063
		'*Key type',
1064
		$pconfig['csr_keytype'],
1065
		array_combine($cert_keytypes, $cert_keytypes)
1066
	));
1067
1068 dace81a7 Viktor Gurov
	$group = new Form_Group($i == 0 ? '*Key length':'');
1069 e0f8d364 Viktor Gurov
	$group->addClass('csr_rsakeys');
1070 dace81a7 Viktor Gurov
	$group->add(new Form_Select(
1071 b35250d9 NewEraCracker
		'csr_keylen',
1072 dace81a7 Viktor Gurov
		null,
1073 b35250d9 NewEraCracker
		$pconfig['csr_keylen'],
1074
		array_combine($cert_keylens, $cert_keylens)
1075 3f0b7bc3 jim-p
	))->setHelp('The length to use when generating a new RSA key, in bits. %1$s' .
1076
		'The Key Length should not be lower than 2048 or some platforms ' .
1077
		'may consider the certificate invalid.', '<br/>');
1078 dace81a7 Viktor Gurov
	$section->add($group);
1079
1080 e0f8d364 Viktor Gurov
	$group = new Form_Group($i == 0 ? '*Elliptic Curve Name':'');
1081 2d13c7fc Viktor Gurov
	$group->addClass('csr_ecnames');
1082 dace81a7 Viktor Gurov
	$group->add(new Form_Select(
1083 e0f8d364 Viktor Gurov
		'csr_ecname',
1084 dace81a7 Viktor Gurov
		null,
1085 e0f8d364 Viktor Gurov
		$pconfig['csr_ecname'],
1086 cffcf9bf jim-p
		$openssl_ecnames
1087 dace81a7 Viktor Gurov
	));
1088
	$section->add($group);
1089 64cc39d3 Matthew Grooms
1090 b35250d9 NewEraCracker
	$section->addInput(new Form_Select(
1091
		'csr_digest_alg',
1092 153c3aa6 Phil Davis
		'*Digest Algorithm',
1093 b35250d9 NewEraCracker
		$pconfig['csr_digest_alg'],
1094
		array_combine($openssl_digest_algs, $openssl_digest_algs)
1095 3f0b7bc3 jim-p
	))->setHelp('The digest method used when the certificate is signed. %1$s' .
1096 e1267c0f jim-p
		'The best practice is to use SHA256 or higher. '.
1097
		'Some services and platforms, such as the GUI web server and OpenVPN, consider weaker digest algorithms invalid.', '<br/>');
1098 b49f31d0 Sjon Hortensius
1099 26e3967a jim-p
	$section->addInput(new Form_Input(
1100
		'csr_dn_commonname',
1101
		'*Common Name',
1102
		'text',
1103
		$pconfig['csr_dn_commonname'],
1104
		['placeholder' => 'e.g. internal-ca']
1105
	));
1106
1107
	$section->addInput(new Form_StaticText(
1108
		null,
1109
		gettext('The following certificate subject components are optional and may be left blank.')
1110
	));
1111
1112 b35250d9 NewEraCracker
	$section->addInput(new Form_Select(
1113
		'csr_dn_country',
1114 80d50253 jim-p
		'Country Code',
1115 b35250d9 NewEraCracker
		$pconfig['csr_dn_country'],
1116 232b1a69 Renato Botelho
		get_cert_country_codes()
1117 b35250d9 NewEraCracker
	));
1118 bf9d50e8 Stephen Beaver
1119 b35250d9 NewEraCracker
	$section->addInput(new Form_Input(
1120
		'csr_dn_state',
1121 80d50253 jim-p
		'State or Province',
1122 b35250d9 NewEraCracker
		'text',
1123
		$pconfig['csr_dn_state'],
1124
		['placeholder' => 'e.g. Texas']
1125
	));
1126 bf9d50e8 Stephen Beaver
1127 b35250d9 NewEraCracker
	$section->addInput(new Form_Input(
1128
		'csr_dn_city',
1129 80d50253 jim-p
		'City',
1130 b35250d9 NewEraCracker
		'text',
1131
		$pconfig['csr_dn_city'],
1132
		['placeholder' => 'e.g. Austin']
1133
	));
1134 bf9d50e8 Stephen Beaver
1135 b35250d9 NewEraCracker
	$section->addInput(new Form_Input(
1136
		'csr_dn_organization',
1137 80d50253 jim-p
		'Organization',
1138 b35250d9 NewEraCracker
		'text',
1139
		$pconfig['csr_dn_organization'],
1140 da0f70ed jim-p
		['placeholder' => 'e.g. My Company Inc']
1141
	));
1142
1143
	$section->addInput(new Form_Input(
1144
		'csr_dn_organizationalunit',
1145
		'Organizational Unit',
1146
		'text',
1147
		$pconfig['csr_dn_organizationalunit'],
1148
		['placeholder' => 'e.g. My Department Name (optional)']
1149 b35250d9 NewEraCracker
	));
1150 b49f31d0 Sjon Hortensius
1151 0c82b8c2 jim-p
	$form->add($section);
1152
	$section = new Form_Section('Choose an Existing Certificate');
1153
	$section->addClass('toggle-existing collapse');
1154
1155
	$existCerts = array();
1156
1157 ca4456b9 jim-p
	foreach ($config['cert'] as $cert) {
1158
		if (!is_array($cert) || empty($cert)) {
1159
			continue;
1160
		}
1161 843ee1ac jim-p
1162
		if (isset($userid) &&
1163
		    in_array($cert['refid'], config_get_path("system/user/{$userid}/cert", []))) {
1164
			continue;
1165 0c82b8c2 jim-p
		}
1166
1167
		$ca = lookup_ca($cert['caref']);
1168
		if ($ca) {
1169
			$cert['descr'] .= " (CA: {$ca['descr']})";
1170
		}
1171
1172
		if (cert_in_use($cert['refid'])) {
1173
			$cert['descr'] .= " (In Use)";
1174
		}
1175
		if (is_cert_revoked($cert)) {
1176
			$cert['descr'] .= " (Revoked)";
1177
		}
1178
1179
		$existCerts[ $cert['refid'] ] = $cert['descr'];
1180
	}
1181
1182
	$section->addInput(new Form_Select(
1183
		'certref',
1184
		'*Existing Certificates',
1185
		$pconfig['certref'],
1186
		$existCerts
1187
	));
1188
1189
	$form->add($section);
1190
1191
	$section = new Form_Section('Certificate Attributes');
1192
	$section->addClass('toggle-external toggle-internal toggle-sign collapse');
1193
1194
	$section->addInput(new Form_StaticText(
1195
		gettext('Attribute Notes'),
1196
		'<span class="help-block">'.
1197
		gettext('The following attributes are added to certificates and ' .
1198
		'requests when they are created or signed. These attributes behave ' .
1199
		'differently depending on the selected mode.') .
1200
		'<br/><br/>' .
1201
		'<span class="toggle-internal collapse">' . gettext('For Internal Certificates, these attributes are added directly to the certificate as shown.') . '</span>' .
1202
		'<span class="toggle-external collapse">' .
1203
		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. ') .
1204
		'<br/><br/>' .
1205
		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>' .
1206
		'<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>' .
1207
		'</span>'
1208
	));
1209
1210
	$section->addInput(new Form_Select(
1211
		'type',
1212
		'*Certificate Type',
1213
		$pconfig['type'],
1214
		$cert_types
1215
	))->setHelp('Add type-specific usage attributes to the signed certificate.' .
1216
		' Used for placing usage restrictions on, or granting abilities to, ' .
1217
		'the signed certificate.');
1218
1219 282b6c66 jim-p
	if (empty($pconfig['altnames']['item'])) {
1220
		$pconfig['altnames']['item'] = array(
1221
			array('type' => null, 'value' => null)
1222
		);
1223
	}
1224
1225
	$counter = 0;
1226
	$numrows = count($pconfig['altnames']['item']) - 1;
1227
1228
	foreach ($pconfig['altnames']['item'] as $item) {
1229
1230
		$group = new Form_Group($counter == 0 ? 'Alternative Names':'');
1231
1232
		$group->add(new Form_Select(
1233
			'altname_type' . $counter,
1234
			'Type',
1235
			$item['type'],
1236
			$cert_altname_types
1237
		))->setHelp(($counter == $numrows) ? 'Type':null);
1238
1239
		$group->add(new Form_Input(
1240
			'altname_value' . $counter,
1241
			null,
1242
			'text',
1243
			$item['value']
1244
		))->setHelp(($counter == $numrows) ? 'Value':null);
1245
1246
		$group->add(new Form_Button(
1247
			'deleterow' . $counter,
1248
			'Delete',
1249
			null,
1250
			'fa-trash'
1251
		))->addClass('btn-warning');
1252
1253
		$group->addClass('repeatable');
1254
1255 0c82b8c2 jim-p
		$group->setHelp('Enter additional identifiers for the certificate ' .
1256
			'in this list. The Common Name field is automatically ' .
1257
			'added to the certificate as an Alternative Name. ' .
1258
			'The signing CA may ignore or change these values.');
1259 282b6c66 jim-p
1260
		$section->add($group);
1261
1262
		$counter++;
1263
	}
1264
1265
	$section->addInput(new Form_Button(
1266
		'addrow',
1267 bfa5cfef jim-p
		'Add SAN Row',
1268 282b6c66 jim-p
		null,
1269
		'fa-plus'
1270
	))->addClass('btn-success');
1271
1272 b35250d9 NewEraCracker
	$form->add($section);
1273 b49f31d0 Sjon Hortensius
1274 2e4372e3 Viktor G
	if (($act == 'edit') && !empty($pconfig['key'])) {
1275 96773352 jim-p
		$form->addGlobal(new Form_Button(
1276
			'exportpkey',
1277
			'Export Private Key',
1278
			null,
1279
			'fa-key'
1280
		))->addClass('btn-primary');
1281
		$form->addGlobal(new Form_Button(
1282
			'exportp12',
1283
			'Export PKCS#12',
1284
			null,
1285
			'fa-archive'
1286
		))->addClass('btn-primary');
1287
	}
1288 b49f31d0 Sjon Hortensius
1289 b35250d9 NewEraCracker
	print $form;
1290 64cc39d3 Matthew Grooms
1291 7e83055a jim-p
} elseif ($act == "csr" || (($_POST['save'] == gettext("Update")) && $input_errors)) {
1292 8f58b51b jim-p
	$form = new Form(false);
1293 308f0665 NewEraCracker
	$form->setAction('system_certmanager.php?act=csr');
1294 b29c322c Stephen Beaver
1295 5f88f964 k-paulius
	$section = new Form_Section("Complete Signing Request for " . $pconfig['descr']);
1296 b29c322c Stephen Beaver
1297 ba5c55e9 Stephen Beaver
	$section->addInput(new Form_Input(
1298
		'descr',
1299 153c3aa6 Phil Davis
		'*Descriptive name',
1300 ba5c55e9 Stephen Beaver
		'text',
1301
		$pconfig['descr']
1302 f16d3f4d jim-p
	))->setHelp('The name of this entry as displayed in the GUI for reference.%s' .
1303
		'This name can contain spaces but it cannot contain any of the ' .
1304
		'following characters: %s', '<br/>', "?, >, <, &, /, \, \", '");
1305 ba5c55e9 Stephen Beaver
1306 b29c322c Stephen Beaver
	$section->addInput(new Form_Textarea(
1307
		'csr',
1308
		'Signing request data',
1309
		$pconfig['csr']
1310
	))->setReadonly()
1311 af28e231 Stephen Beaver
	  ->setWidth(7)
1312 813c6673 NOYB
	  ->setHelp('Copy the certificate signing data from here and forward it to a certificate authority for signing.');
1313 b29c322c Stephen Beaver
1314
	$section->addInput(new Form_Textarea(
1315
		'cert',
1316 153c3aa6 Phil Davis
		'*Final certificate data',
1317 b29c322c Stephen Beaver
		$pconfig['cert']
1318 af28e231 Stephen Beaver
	))->setWidth(7)
1319 813c6673 NOYB
	  ->setHelp('Paste the certificate received from the certificate authority here.');
1320 b29c322c Stephen Beaver
1321 f0b38e39 jim-p
	if (isset($id) && $thiscert) {
1322 ee12dd78 Peter Feichtinger
		$form->addGlobal(new Form_Input(
1323 b29c322c Stephen Beaver
			'id',
1324
			null,
1325
			'hidden',
1326
			$id
1327 ee12dd78 Peter Feichtinger
		));
1328 b29c322c Stephen Beaver
1329 ee12dd78 Peter Feichtinger
		$form->addGlobal(new Form_Input(
1330 b29c322c Stephen Beaver
			'act',
1331
			null,
1332
			'hidden',
1333
			'csr'
1334 ee12dd78 Peter Feichtinger
		));
1335
	}
1336 b29c322c Stephen Beaver
1337
	$form->add($section);
1338 8f58b51b jim-p
1339
	$form->addGlobal(new Form_Button(
1340 141d8913 jim-p
		'save',
1341 faab522f Renato Botelho
		'Update',
1342 8f58b51b jim-p
		null,
1343
		'fa-save'
1344
	))->addClass('btn-primary');
1345
1346 b29c322c Stephen Beaver
	print($form);
1347
} else {
1348
?>
1349 14973058 jim-p
<div class="panel panel-default" id="search-panel">
1350
	<div class="panel-heading">
1351
		<h2 class="panel-title">
1352
			<?=gettext('Search')?>
1353
			<span class="widget-heading-icon pull-right">
1354
				<a data-toggle="collapse" href="#search-panel_panel-body">
1355
					<i class="fa fa-plus-circle"></i>
1356
				</a>
1357
			</span>
1358
		</h2>
1359
	</div>
1360
	<div id="search-panel_panel-body" class="panel-body collapse in">
1361
		<div class="form-group">
1362
			<label class="col-sm-2 control-label">
1363
				<?=gettext("Search term")?>
1364
			</label>
1365
			<div class="col-sm-5"><input class="form-control" name="searchstr" id="searchstr" type="text"/></div>
1366
			<div class="col-sm-2">
1367
				<select id="where" class="form-control">
1368
					<option value="0"><?=gettext("Name")?></option>
1369
					<option value="1"><?=gettext("Distinguished Name")?></option>
1370
					<option value="2" selected><?=gettext("Both")?></option>
1371
				</select>
1372
			</div>
1373
			<div class="col-sm-3">
1374
				<a id="btnsearch" title="<?=gettext("Search")?>" class="btn btn-primary btn-sm"><i class="fa fa-search icon-embed-btn"></i><?=gettext("Search")?></a>
1375
				<a id="btnclear" title="<?=gettext("Clear")?>" class="btn btn-info btn-sm"><i class="fa fa-undo icon-embed-btn"></i><?=gettext("Clear")?></a>
1376
			</div>
1377
			<div class="col-sm-10 col-sm-offset-2">
1378 f30da999 jim-p
				<span class="help-block"><?=gettext('Enter a search string or *nix regular expression to search certificate names and distinguished names.')?></span>
1379 14973058 jim-p
			</div>
1380
		</div>
1381
	</div>
1382
</div>
1383 060ed238 Stephen Beaver
<div class="panel panel-default">
1384
	<div class="panel-heading"><h2 class="panel-title"><?=gettext('Certificates')?></h2></div>
1385
	<div class="panel-body">
1386
		<div class="table-responsive">
1387 14973058 jim-p
		<table class="table table-striped table-hover sortable-theme-bootstrap" data-sortable>
1388 060ed238 Stephen Beaver
			<thead>
1389
				<tr>
1390
					<th><?=gettext("Name")?></th>
1391
					<th><?=gettext("Issuer")?></th>
1392
					<th><?=gettext("Distinguished Name")?></th>
1393
					<th><?=gettext("In Use")?></th>
1394 4db1f211 Stephen Beaver
1395 060ed238 Stephen Beaver
					<th class="col-sm-2"><?=gettext("Actions")?></th>
1396
				</tr>
1397
			</thead>
1398
			<tbody>
1399 b29c322c Stephen Beaver
<?php
1400 4db1f211 Stephen Beaver
1401
$pluginparams = array();
1402
$pluginparams['type'] = 'certificates';
1403
$pluginparams['event'] = 'used_certificates';
1404
$certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
1405 46bd32bb Steve Beaver
foreach ($a_cert as $cert):
1406
	if (!is_array($cert) || empty($cert)) {
1407
		continue;
1408
	}
1409
	$name = htmlspecialchars($cert['descr']);
1410
	if ($cert['crt']) {
1411
		$subj = cert_get_subject($cert['crt']);
1412
		$issuer = cert_get_issuer($cert['crt']);
1413
		$purpose = cert_get_purpose($cert['crt']);
1414
1415
		if ($subj == $issuer) {
1416
			$caname = '<i>'. gettext("self-signed") .'</i>';
1417
		} else {
1418
			$caname = '<i>'. gettext("external").'</i>';
1419
		}
1420 b29c322c Stephen Beaver
1421 46bd32bb Steve Beaver
		$subj = htmlspecialchars(cert_escape_x509_chars($subj, true));
1422
	} else {
1423
		$subj = "";
1424
		$issuer = "";
1425
		$purpose = "";
1426
		$startdate = "";
1427
		$enddate = "";
1428
		$caname = "<em>" . gettext("private key only") . "</em>";
1429
	}
1430
1431
	if ($cert['csr']) {
1432
		$subj = htmlspecialchars(cert_escape_x509_chars(csr_get_subject($cert['csr']), true));
1433
		$caname = "<em>" . gettext("external - signature pending") . "</em>";
1434
	}
1435
1436
	$ca = lookup_ca($cert['caref']);
1437
	if ($ca) {
1438 2fe0e0fa jim-p
		$caname = htmlspecialchars($ca['descr']);
1439 46bd32bb Steve Beaver
	}
1440 b29c322c Stephen Beaver
?>
1441 060ed238 Stephen Beaver
				<tr>
1442 46bd32bb Steve Beaver
					<td>
1443
						<?=$name?><br />
1444
						<?php if ($cert['type']): ?>
1445
							<i><?=$cert_types[$cert['type']]?></i><br />
1446
						<?php endif?>
1447
						<?php if (is_array($purpose)): ?>
1448
							CA: <b><?=$purpose['ca']?></b><br/>
1449
							<?=gettext("Server")?>: <b><?=$purpose['server']?></b><br/>
1450
						<?php endif?>
1451
					</td>
1452
					<td><?=$caname?></td>
1453
					<td>
1454
						<?=$subj?>
1455
						<?= cert_print_infoblock($cert); ?>
1456
						<?php cert_print_dates($cert);?>
1457
					</td>
1458
					<td>
1459
						<?php if (is_cert_revoked($cert)): ?>
1460
							<i><?=gettext("Revoked")?></i>
1461
						<?php endif?>
1462
						<?php if (is_webgui_cert($cert['refid'])): ?>
1463
							<?=gettext("webConfigurator")?>
1464
						<?php endif?>
1465
						<?php if (is_user_cert($cert['refid'])): ?>
1466
							<?=gettext("User Cert")?>
1467
						<?php endif?>
1468
						<?php if (is_openvpn_server_cert($cert['refid'])): ?>
1469
							<?=gettext("OpenVPN Server")?>
1470
						<?php endif?>
1471
						<?php if (is_openvpn_client_cert($cert['refid'])): ?>
1472
							<?=gettext("OpenVPN Client")?>
1473
						<?php endif?>
1474
						<?php if (is_ipsec_cert($cert['refid'])): ?>
1475
							<?=gettext("IPsec Tunnel")?>
1476
						<?php endif?>
1477
						<?php if (is_captiveportal_cert($cert['refid'])): ?>
1478
							<?=gettext("Captive Portal")?>
1479
						<?php endif?>
1480
						<?php if (is_unbound_cert($cert['refid'])): ?>
1481
							<?=gettext("DNS Resolver")?>
1482
						<?php endif?>
1483
						<?php echo cert_usedby_description($cert['refid'], $certificates_used_by_packages); ?>
1484 060ed238 Stephen Beaver
					</td>
1485
					<td>
1486
						<?php if (!$cert['csr']): ?>
1487 96773352 jim-p
							<a href="system_certmanager.php?act=edit&amp;id=<?=$cert['refid']?>" class="fa fa-pencil" title="<?=gettext("Edit Certificate")?>"></a>
1488 f0b38e39 jim-p
							<a href="system_certmanager.php?act=exp&amp;id=<?=$cert['refid']?>" class="fa fa-certificate" title="<?=gettext("Export Certificate")?>"></a>
1489 4594038a Steve Beaver
							<?php if ($cert['prv']): ?>
1490 f0b38e39 jim-p
								<a href="system_certmanager.php?act=key&amp;id=<?=$cert['refid']?>" class="fa fa-key" title="<?=gettext("Export Key")?>"></a>
1491 9efec277 Jim Pingle
								<a href="system_certmanager.php?act=p12&amp;id=<?=$cert['refid']?>" class="fa fa-archive" title="<?=gettext("Export PCKS#12 Archive without Encryption")?>"></a>
1492 4594038a Steve Beaver
							<?php endif?>
1493 03a84081 jim-p
							<?php if (is_cert_locally_renewable($cert)): ?>
1494
								<a href="system_certmanager_renew.php?type=cert&amp;refid=<?=$cert['refid']?>" class="fa fa-repeat" title="<?=gettext("Reissue/Renew")?>"></a>
1495 2e4372e3 Viktor G
							<?php endif ?>
1496 060ed238 Stephen Beaver
						<?php else: ?>
1497 f0b38e39 jim-p
							<a href="system_certmanager.php?act=csr&amp;id=<?=$cert['refid']?>" class="fa fa-pencil" title="<?=gettext("Update CSR")?>"></a>
1498
							<a href="system_certmanager.php?act=req&amp;id=<?=$cert['refid']?>" class="fa fa-sign-in" title="<?=gettext("Export Request")?>"></a>
1499
							<a href="system_certmanager.php?act=key&amp;id=<?=$cert['refid']?>" class="fa fa-key" title="<?=gettext("Export Key")?>"></a>
1500 060ed238 Stephen Beaver
						<?php endif?>
1501
						<?php if (!cert_in_use($cert['refid'])): ?>
1502 f0b38e39 jim-p
							<a href="system_certmanager.php?act=del&amp;id=<?=$cert['refid']?>" class="fa fa-trash" title="<?=gettext("Delete Certificate")?>" usepost></a>
1503 060ed238 Stephen Beaver
						<?php endif?>
1504
					</td>
1505
				</tr>
1506 4db1f211 Stephen Beaver
<?php
1507
	endforeach; ?>
1508 060ed238 Stephen Beaver
			</tbody>
1509
		</table>
1510
		</div>
1511
	</div>
1512 b29c322c Stephen Beaver
</div>
1513
1514
<nav class="action-buttons">
1515 4611e283 Steve Beaver
	<a href="?act=new" class="btn btn-success btn-sm">
1516 b29c322c Stephen Beaver
		<i class="fa fa-plus icon-embed-btn"></i>
1517 2052d3e2 Steve Beaver
		<?=gettext("Add/Sign")?>
1518 b29c322c Stephen Beaver
	</a>
1519
</nav>
1520 14973058 jim-p
<script type="text/javascript">
1521
//<![CDATA[
1522
1523
events.push(function() {
1524
1525
	// Make these controls plain buttons
1526
	$("#btnsearch").prop('type', 'button');
1527
	$("#btnclear").prop('type', 'button');
1528
1529
	// Search for a term in the entry name and/or dn
1530
	$("#btnsearch").click(function() {
1531
		var searchstr = $('#searchstr').val().toLowerCase();
1532
		var table = $("table tbody");
1533
		var where = $('#where').val();
1534
1535
		table.find('tr').each(function (i) {
1536
			var $tds = $(this).find('td'),
1537
				shortname = $tds.eq(0).text().trim().toLowerCase(),
1538
				dn = $tds.eq(2).text().trim().toLowerCase();
1539
1540
			regexp = new RegExp(searchstr);
1541
			if (searchstr.length > 0) {
1542
				if (!(regexp.test(shortname) && (where != 1)) && !(regexp.test(dn) && (where != 0))) {
1543
					$(this).hide();
1544
				} else {
1545
					$(this).show();
1546
				}
1547
			} else {
1548
				$(this).show();	// A blank search string shows all
1549
			}
1550
		});
1551
	});
1552
1553
	// Clear the search term and unhide all rows (that were hidden during a previous search)
1554
	$("#btnclear").click(function() {
1555
		var table = $("table tbody");
1556
1557
		$('#searchstr').val("");
1558
1559
		table.find('tr').each(function (i) {
1560
			$(this).show();
1561
		});
1562
	});
1563
1564
	// Hitting the enter key will do the same as clicking the search button
1565
	$("#searchstr").on("keyup", function (event) {
1566
		if (event.keyCode == 13) {
1567
			$("#btnsearch").get(0).click();
1568
		}
1569
	});
1570
});
1571
//]]>
1572
</script>
1573 e9258698 NewEraCracker
<?php
1574 b29c322c Stephen Beaver
	include("foot.inc");
1575
	exit;
1576
}
1577
1578
1579 51583438 Stephen Beaver
?>
1580 8fd9052f Colin Fleming
<script type="text/javascript">
1581 51583438 Stephen Beaver
//<![CDATA[
1582 78863416 Phil Davis
events.push(function() {
1583 bf9d50e8 Stephen Beaver
1584 96d78012 Viktor Gurov
	$('.import_type_toggle').click(function() {
1585
		var x509 = (this.value === 'x509');
1586
		hideInput('cert', !x509);
1587
		setRequired('cert', x509);
1588
		hideInput('key', !x509);
1589
		setRequired('key', x509);
1590
		hideInput('pkcs12_cert', x509);
1591
		setRequired('pkcs12_cert', !x509);
1592
		hideInput('pkcs12_pass', x509);
1593
		hideCheckbox('pkcs12_intermediate', x509);
1594
	});
1595
	if ($('input[name=import_type]:checked').val() == 'x509') {
1596
		hideInput('pkcs12_cert', true);
1597
		setRequired('pkcs12_cert', false);
1598
		hideInput('pkcs12_pass', true);
1599
		hideCheckbox('pkcs12_intermediate', true);
1600
		hideInput('cert', false);
1601
		setRequired('cert', true);
1602
		hideInput('key', false);
1603
		setRequired('key', true);
1604 e7e4ba5a Viktor G
	} else if ($('input[name=import_type]:checked').val() == 'pkcs12') {
1605 96d78012 Viktor Gurov
		hideInput('cert', true);
1606
		setRequired('cert', false);
1607
		hideInput('key', true);
1608
		setRequired('key', false);
1609
		setRequired('pkcs12_cert', false);
1610
	}
1611
1612 51583438 Stephen Beaver
<?php if ($internal_ca_count): ?>
1613
	function internalca_change() {
1614
1615
		caref = $('#caref').val();
1616
1617
		switch (caref) {
1618
<?php
1619
			foreach ($a_ca as $ca):
1620
				if (!$ca['prv']) {
1621
					continue;
1622
				}
1623
1624 746c9afc jim-p
				$subject = @cert_get_subject_hash($ca['crt']);
1625
				if (!is_array($subject) || empty($subject)) {
1626
					continue;
1627
				}
1628 51583438 Stephen Beaver
?>
1629
				case "<?=$ca['refid'];?>":
1630 1ec79365 jim-p
					$('#dn_country').val(<?=json_encode(cert_escape_x509_chars($subject['C'], true));?>);
1631
					$('#dn_state').val(<?=json_encode(cert_escape_x509_chars($subject['ST'], true));?>);
1632
					$('#dn_city').val(<?=json_encode(cert_escape_x509_chars($subject['L'], true));?>);
1633
					$('#dn_organization').val(<?=json_encode(cert_escape_x509_chars($subject['O'], true));?>);
1634
					$('#dn_organizationalunit').val(<?=json_encode(cert_escape_x509_chars($subject['OU'], true));?>);
1635 51583438 Stephen Beaver
					break;
1636
<?php
1637
			endforeach;
1638
?>
1639
		}
1640
	}
1641
1642 2052d3e2 Steve Beaver
	function set_csr_ro() {
1643 b078cd59 Steve Beaver
		var newcsr = ($('#csrtosign').val() == "new");
1644 65d735f0 Steve Beaver
1645
		$('#csrpaste').attr('readonly', !newcsr);
1646 55047259 Steve Beaver
		$('#keypaste').attr('readonly', !newcsr);
1647 65d735f0 Steve Beaver
		setRequired('csrpaste', newcsr);
1648 2052d3e2 Steve Beaver
	}
1649
1650 3f0b7bc3 jim-p
	function check_lifetime() {
1651
		var maxserverlife = <?= $cert_strict_values['max_server_cert_lifetime'] ?>;
1652
		var ltid = '#lifetime';
1653
		if ($('#method').val() == "sign") {
1654
			ltid = '#csrsign_lifetime';
1655
		}
1656
		if (($('#type').val() == "server") && (parseInt($(ltid).val()) > maxserverlife)) {
1657
			$(ltid).parent().parent().removeClass("text-normal").addClass("text-warning");
1658
			$(ltid).removeClass("text-normal").addClass("text-warning");
1659
		} else {
1660
			$(ltid).parent().parent().removeClass("text-warning").addClass("text-normal");
1661
			$(ltid).removeClass("text-warning").addClass("text-normal");
1662
		}
1663
	}
1664
	function check_keylen() {
1665
		var min_keylen = <?= $cert_strict_values['min_private_key_bits'] ?>;
1666
		var klid = '#keylen';
1667
		if ($('#method').val() == "external") {
1668
			klid = '#csr_keylen';
1669
		}
1670
		/* Color the Parent/Label */
1671
		if (parseInt($(klid).val()) < min_keylen) {
1672
			$(klid).parent().parent().removeClass("text-normal").addClass("text-warning");
1673
		} else {
1674
			$(klid).parent().parent().removeClass("text-warning").addClass("text-normal");
1675
		}
1676
		/* Color individual options */
1677
		$(klid + " option").filter(function() {
1678
			return parseInt($(this).val()) < min_keylen;
1679
		}).removeClass("text-normal").addClass("text-warning").siblings().removeClass("text-warning").addClass("text-normal");
1680
	}
1681
1682
	function check_digest() {
1683
		var weak_algs = <?= json_encode($cert_strict_values['digest_blacklist']) ?>;
1684
		var daid = '#digest_alg';
1685
		if ($('#method').val() == "external") {
1686
			daid = '#csr_digest_alg';
1687
		} else if ($('#method').val() == "sign") {
1688
			daid = '#csrsign_digest_alg';
1689
		}
1690
		/* Color the Parent/Label */
1691
		if (jQuery.inArray($(daid).val(), weak_algs) > -1) {
1692
			$(daid).parent().parent().removeClass("text-normal").addClass("text-warning");
1693
		} else {
1694
			$(daid).parent().parent().removeClass("text-warning").addClass("text-normal");
1695
		}
1696
		/* Color individual options */
1697
		$(daid + " option").filter(function() {
1698
			return (jQuery.inArray($(this).val(), weak_algs) > -1);
1699
		}).removeClass("text-normal").addClass("text-warning").siblings().removeClass("text-warning").addClass("text-normal");
1700
	}
1701
1702 eef93144 Jared Dillard
	// ---------- Click checkbox handlers ---------------------------------------------------------
1703 f74457df Stephen Beaver
1704 3f0b7bc3 jim-p
	$('#type').on('change', function() {
1705
		check_lifetime();
1706
	});
1707
	$('#method').on('change', function() {
1708
		check_lifetime();
1709
		check_keylen();
1710
		check_digest();
1711
	});
1712
	$('#lifetime').on('change', function() {
1713
		check_lifetime();
1714
	});
1715
	$('#csrsign_lifetime').on('change', function() {
1716
		check_lifetime();
1717
	});
1718
1719
	$('#keylen').on('change', function() {
1720
		check_keylen();
1721
	});
1722
	$('#csr_keylen').on('change', function() {
1723
		check_keylen();
1724
	});
1725
1726
	$('#digest_alg').on('change', function() {
1727
		check_digest();
1728
	});
1729
	$('#csr_digest_alg').on('change', function() {
1730
		check_digest();
1731
	});
1732
1733 51583438 Stephen Beaver
	$('#caref').on('change', function() {
1734
		internalca_change();
1735
	});
1736
1737 2052d3e2 Steve Beaver
	$('#csrtosign').change(function () {
1738
		set_csr_ro();
1739
	});
1740
1741 dace81a7 Viktor Gurov
	function change_keytype() {
1742 e655d548 jim-p
		hideClass('rsakeys', ($('#keytype').val() != 'RSA'));
1743
		hideClass('ecnames', ($('#keytype').val() != 'ECDSA'));
1744
	}
1745 dace81a7 Viktor Gurov
1746
	$('#keytype').change(function () {
1747 e655d548 jim-p
		change_keytype();
1748
	});
1749 dace81a7 Viktor Gurov
1750
	function change_csrkeytype() {
1751 e655d548 jim-p
		hideClass('csr_rsakeys', ($('#csr_keytype').val() != 'RSA'));
1752
		hideClass('csr_ecnames', ($('#csr_keytype').val() != 'ECDSA'));
1753
	}
1754 dace81a7 Viktor Gurov
1755
	$('#csr_keytype').change(function () {
1756 e655d548 jim-p
		change_csrkeytype();
1757
	});
1758 dace81a7 Viktor Gurov
1759 eef93144 Jared Dillard
	// ---------- On initial page load ------------------------------------------------------------
1760
1761 51583438 Stephen Beaver
	internalca_change();
1762 2052d3e2 Steve Beaver
	set_csr_ro();
1763 dace81a7 Viktor Gurov
	change_keytype();
1764
	change_csrkeytype();
1765 3f0b7bc3 jim-p
	check_lifetime();
1766
	check_keylen();
1767
	check_digest();
1768 51583438 Stephen Beaver
1769 0bc61baa Stephen Beaver
	// Suppress "Delete row" button if there are fewer than two rows
1770
	checkLastRow();
1771
1772 dace81a7 Viktor Gurov
1773 51583438 Stephen Beaver
<?php endif; ?>
1774
1775
1776
});
1777
//]]>
1778
</script>
1779
<?php
1780 0edcccc3 Daniel Seebald
include('foot.inc');