Project

General

Profile

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