Project

General

Profile

Download (26.7 KB) Statistics
| Branch: | Tag: | Revision:
1 64cc39d3 Matthew Grooms
<?php
2
/*
3 ce77a9c4 Phil Davis
	system_certmanager.php
4
5
	Copyright (C) 2008 Shrew Soft Inc.
6
	Copyright (C) 2013-2015 Electric Sheep Fencing, LP
7
	All rights reserved.
8
9
	Redistribution and use in source and binary forms, with or without
10
	modification, are permitted provided that the following conditions are met:
11
12
	1. Redistributions of source code must retain the above copyright notice,
13
	   this list of conditions and the following disclaimer.
14
15
	2. Redistributions in binary form must reproduce the above copyright
16
	   notice, this list of conditions and the following disclaimer in the
17
	   documentation and/or other materials provided with the distribution.
18
19
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
	POSSIBILITY OF SUCH DAMAGE.
29 64cc39d3 Matthew Grooms
*/
30 1d333258 Scott Ullrich
/*
31 51583438 Stephen Beaver
	pfSense_MODULE: certificate_manager
32 1d333258 Scott Ullrich
*/
33 64cc39d3 Matthew Grooms
34
##|+PRIV
35
##|*IDENT=page-system-certmanager
36
##|*NAME=System: Certificate Manager
37
##|*DESCR=Allow access to the 'System: Certificate Manager' page.
38
##|*MATCH=system_certmanager.php*
39
##|-PRIV
40
41
require("guiconfig.inc");
42 14f5ae08 Ermal Lu?i
require_once("certs.inc");
43 64cc39d3 Matthew Grooms
44
$cert_methods = array(
45 ad9b5c67 jim-p
	"import" => gettext("Import an existing Certificate"),
46 a37753d7 Vinicius Coque
	"internal" => gettext("Create an internal Certificate"),
47 ad9b5c67 jim-p
	"external" => gettext("Create a Certificate Signing Request"),
48
);
49 64cc39d3 Matthew Grooms
50 56b1ed39 Phil Davis
$cert_keylens = array("512", "1024", "2048", "4096");
51
$cert_types = array(
52
	"ca" => "Certificate Authority",
53
	"server" => "Server Certificate",
54
	"user" => "User Certificate");
55 64cc39d3 Matthew Grooms
56 2f65de89 jim-p
$altname_types = array("DNS", "IP", "email", "URI");
57 84197cec jim-p
$openssl_digest_algs = array("sha1", "sha224", "sha256", "sha384", "sha512");
58 2f65de89 jim-p
59 51e4f7a3 Vinicius Coque
$pgtitle = array(gettext("System"), gettext("Certificate Manager"));
60 64cc39d3 Matthew Grooms
61 56b1ed39 Phil Davis
if (is_numericint($_GET['userid'])) {
62 e41ec584 Renato Botelho
	$userid = $_GET['userid'];
63 56b1ed39 Phil Davis
}
64
if (isset($_POST['userid']) && is_numericint($_POST['userid'])) {
65 ad9b5c67 jim-p
	$userid = $_POST['userid'];
66 56b1ed39 Phil Davis
}
67 e41ec584 Renato Botelho
68
if (isset($userid)) {
69 ad9b5c67 jim-p
	$cert_methods["existing"] = gettext("Choose an existing certificate");
70 56b1ed39 Phil Davis
	if (!is_array($config['system']['user'])) {
71 ad9b5c67 jim-p
		$config['system']['user'] = array();
72 56b1ed39 Phil Davis
	}
73 ad9b5c67 jim-p
	$a_user =& $config['system']['user'];
74
}
75
76 56b1ed39 Phil Davis
if (is_numericint($_GET['id'])) {
77 e41ec584 Renato Botelho
	$id = $_GET['id'];
78 56b1ed39 Phil Davis
}
79
if (isset($_POST['id']) && is_numericint($_POST['id'])) {
80 64cc39d3 Matthew Grooms
	$id = $_POST['id'];
81 56b1ed39 Phil Davis
}
82 64cc39d3 Matthew Grooms
83 56b1ed39 Phil Davis
if (!is_array($config['ca'])) {
84 b4e6524c jim-p
	$config['ca'] = array();
85 56b1ed39 Phil Davis
}
86 64cc39d3 Matthew Grooms
87 b4e6524c jim-p
$a_ca =& $config['ca'];
88 64cc39d3 Matthew Grooms
89 56b1ed39 Phil Davis
if (!is_array($config['cert'])) {
90 b4e6524c jim-p
	$config['cert'] = array();
91 56b1ed39 Phil Davis
}
92 64cc39d3 Matthew Grooms
93 b4e6524c jim-p
$a_cert =& $config['cert'];
94 64cc39d3 Matthew Grooms
95
$internal_ca_count = 0;
96 56b1ed39 Phil Davis
foreach ($a_ca as $ca) {
97
	if ($ca['prv']) {
98 64cc39d3 Matthew Grooms
		$internal_ca_count++;
99 56b1ed39 Phil Davis
	}
100
}
101 64cc39d3 Matthew Grooms
102
$act = $_GET['act'];
103 8b35eae5 Stephen Beaver
104 56b1ed39 Phil Davis
if ($_POST['act']) {
105 64cc39d3 Matthew Grooms
	$act = $_POST['act'];
106 56b1ed39 Phil Davis
}
107 64cc39d3 Matthew Grooms
108
if ($act == "del") {
109
110 40e6086a jim-p
	if (!isset($a_cert[$id])) {
111 64cc39d3 Matthew Grooms
		pfSenseHeader("system_certmanager.php");
112
		exit;
113
	}
114
115
	unset($a_cert[$id]);
116
	write_config();
117 b741d2ef jim-p
	$savemsg = sprintf(gettext("Certificate %s successfully deleted"), htmlspecialchars($a_cert[$id]['descr'])) . "<br />";
118 2f51259b jim-p
	pfSenseHeader("system_certmanager.php");
119
	exit;
120 64cc39d3 Matthew Grooms
}
121
122 8b35eae5 Stephen Beaver
123 64cc39d3 Matthew Grooms
if ($act == "new") {
124
	$pconfig['method'] = $_GET['method'];
125
	$pconfig['keylen'] = "2048";
126 28a20fdb jim-p
	$pconfig['digest_alg'] = "sha256";
127 8f07b51c PiBa-NL
	$pconfig['csr_keylen'] = "2048";
128
	$pconfig['csr_digest_alg'] = "sha256";
129 7aaabd69 jim-p
	$pconfig['type'] = "user";
130 cf360495 Chris Buechler
	$pconfig['lifetime'] = "3650";
131 64cc39d3 Matthew Grooms
}
132
133 93823b10 Matthew Grooms
if ($act == "exp") {
134
135
	if (!$a_cert[$id]) {
136
		pfSenseHeader("system_certmanager.php");
137
		exit;
138
	}
139
140 f2a86ca9 jim-p
	$exp_name = urlencode("{$a_cert[$id]['descr']}.crt");
141 93823b10 Matthew Grooms
	$exp_data = base64_decode($a_cert[$id]['crt']);
142
	$exp_size = strlen($exp_data);
143
144
	header("Content-Type: application/octet-stream");
145
	header("Content-Disposition: attachment; filename={$exp_name}");
146
	header("Content-Length: $exp_size");
147
	echo $exp_data;
148
	exit;
149
}
150
151 73fbece8 mgrooms
if ($act == "key") {
152
153
	if (!$a_cert[$id]) {
154
		pfSenseHeader("system_certmanager.php");
155
		exit;
156
	}
157
158 f2a86ca9 jim-p
	$exp_name = urlencode("{$a_cert[$id]['descr']}.key");
159 73fbece8 mgrooms
	$exp_data = base64_decode($a_cert[$id]['prv']);
160
	$exp_size = strlen($exp_data);
161
162
	header("Content-Type: application/octet-stream");
163
	header("Content-Disposition: attachment; filename={$exp_name}");
164
	header("Content-Length: $exp_size");
165
	echo $exp_data;
166
	exit;
167
}
168
169 eaf23c17 jim-p
if ($act == "p12") {
170
	if (!$a_cert[$id]) {
171
		pfSenseHeader("system_certmanager.php");
172
		exit;
173
	}
174
175
	$exp_name = urlencode("{$a_cert[$id]['descr']}.p12");
176 eed5b507 jim-p
	$args = array();
177
	$args['friendly_name'] = $a_cert[$id]['descr'];
178
179
	$ca = lookup_ca($a_cert[$id]['caref']);
180 56b1ed39 Phil Davis
	if ($ca) {
181 eed5b507 jim-p
		$args['extracerts'] = openssl_x509_read(base64_decode($ca['crt']));
182 56b1ed39 Phil Davis
	}
183 eaf23c17 jim-p
184
	$res_crt = openssl_x509_read(base64_decode($a_cert[$id]['crt']));
185
	$res_key = openssl_pkey_get_private(array(0 => base64_decode($a_cert[$id]['prv']) , 1 => ""));
186
187
	$exp_data = "";
188 eed5b507 jim-p
	openssl_pkcs12_export($res_crt, $exp_data, $res_key, null, $args);
189 eaf23c17 jim-p
	$exp_size = strlen($exp_data);
190
191
	header("Content-Type: application/octet-stream");
192
	header("Content-Disposition: attachment; filename={$exp_name}");
193
	header("Content-Length: $exp_size");
194
	echo $exp_data;
195
	exit;
196
}
197
198 64cc39d3 Matthew Grooms
if ($act == "csr") {
199
200
	if (!$a_cert[$id]) {
201
		pfSenseHeader("system_certmanager.php");
202
		exit;
203
	}
204
205 f2a86ca9 jim-p
	$pconfig['descr'] = $a_cert[$id]['descr'];
206 64cc39d3 Matthew Grooms
	$pconfig['csr'] = base64_decode($a_cert[$id]['csr']);
207
}
208
209
if ($_POST) {
210 e64aa6f8 Carlos Eduardo Ramos
	if ($_POST['save'] == gettext("Save")) {
211 21cc2faa Evgeny Yurchenko
		$input_errors = array();
212 64cc39d3 Matthew Grooms
		$pconfig = $_POST;
213
214
		/* input validation */
215 ad9b5c67 jim-p
		if ($pconfig['method'] == "import") {
216 64cc39d3 Matthew Grooms
			$reqdfields = explode(" ",
217 56b1ed39 Phil Davis
				"descr cert key");
218 38fb1109 Vinicius Coque
			$reqdfieldsn = array(
219 56b1ed39 Phil Davis
				gettext("Descriptive name"),
220
				gettext("Certificate data"),
221
				gettext("Key data"));
222
			if ($_POST['cert'] && (!strstr($_POST['cert'], "BEGIN CERTIFICATE") || !strstr($_POST['cert'], "END CERTIFICATE"))) {
223 396cfe2e jim-p
				$input_errors[] = gettext("This certificate does not appear to be valid.");
224 56b1ed39 Phil Davis
			}
225 64cc39d3 Matthew Grooms
		}
226
227
		if ($pconfig['method'] == "internal") {
228
			$reqdfields = explode(" ",
229 56b1ed39 Phil Davis
				"descr caref keylen type lifetime dn_country dn_state dn_city ".
230
				"dn_organization dn_email dn_commonname");
231 38fb1109 Vinicius Coque
			$reqdfieldsn = array(
232 56b1ed39 Phil Davis
				gettext("Descriptive name"),
233
				gettext("Certificate authority"),
234
				gettext("Key length"),
235
				gettext("Certificate Type"),
236
				gettext("Lifetime"),
237
				gettext("Distinguished name Country Code"),
238
				gettext("Distinguished name State or Province"),
239
				gettext("Distinguished name City"),
240
				gettext("Distinguished name Organization"),
241
				gettext("Distinguished name Email Address"),
242
				gettext("Distinguished name Common Name"));
243 64cc39d3 Matthew Grooms
		}
244
245
		if ($pconfig['method'] == "external") {
246
			$reqdfields = explode(" ",
247 56b1ed39 Phil Davis
				"descr csr_keylen csr_dn_country csr_dn_state csr_dn_city ".
248
				"csr_dn_organization csr_dn_email csr_dn_commonname");
249 38fb1109 Vinicius Coque
			$reqdfieldsn = array(
250 56b1ed39 Phil Davis
				gettext("Descriptive name"),
251
				gettext("Key length"),
252
				gettext("Distinguished name Country Code"),
253
				gettext("Distinguished name State or Province"),
254
				gettext("Distinguished name City"),
255
				gettext("Distinguished name Organization"),
256
				gettext("Distinguished name Email Address"),
257
				gettext("Distinguished name Common Name"));
258 64cc39d3 Matthew Grooms
		}
259
260 ad9b5c67 jim-p
		if ($pconfig['method'] == "existing") {
261
			$reqdfields = array("certref");
262
			$reqdfieldsn = array(gettext("Existing Certificate Choice"));
263
		}
264
265 547c56c4 jim-p
		$altnames = array();
266 1e9b4611 Renato Botelho
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
267 eecbeec4 Renato Botelho
		if ($pconfig['method'] != "import" && $pconfig['method'] != "existing") {
268 2f65de89 jim-p
			/* subjectAltNames */
269 b49f31d0 Sjon Hortensius
			foreach ($_POST['altname_value'] as $idx => $value) {
270
				if (empty($value))
271
					continue;
272
273
				$altnames[$idx] = array(
274
					'type' => $_POST['altname_type'][$idx],
275
					'value' => $value
276
				);
277 2f65de89 jim-p
			}
278 edf37d56 Renato Botelho
			$pconfig['altnames']['item'] = $altnames;
279 2f65de89 jim-p
280
			/* Input validation for subjectAltNames */
281
			foreach ($altnames as $idx => $altname) {
282
				switch ($altname['type']) {
283
					case "DNS":
284 56b1ed39 Phil Davis
						if (!is_hostname($altname['value'])) {
285 2f65de89 jim-p
							array_push($input_errors, "DNS subjectAltName values must be valid hostnames or FQDNs");
286 56b1ed39 Phil Davis
						}
287 2f65de89 jim-p
						break;
288
					case "IP":
289 56b1ed39 Phil Davis
						if (!is_ipaddr($altname['value'])) {
290 2f65de89 jim-p
							array_push($input_errors, "IP subjectAltName values must be valid IP Addresses");
291 56b1ed39 Phil Davis
						}
292 2f65de89 jim-p
						break;
293
					case "email":
294 56b1ed39 Phil Davis
						if (empty($altname['value'])) {
295 2f65de89 jim-p
							array_push($input_errors, "You must provide an e-mail address for this type of subjectAltName");
296 56b1ed39 Phil Davis
						}
297
						if (preg_match("/[\!\#\$\%\^\(\)\~\?\>\<\&\/\\\,\"\']/", $altname['value'])) {
298 2f65de89 jim-p
							array_push($input_errors, "The e-mail provided in a subjectAltName contains invalid characters.");
299 56b1ed39 Phil Davis
						}
300 2f65de89 jim-p
						break;
301
					case "URI":
302
						/* Close enough? */
303 56b1ed39 Phil Davis
						if (!is_URL($altname['value'])) {
304 2f65de89 jim-p
							$input_errors[] = "URI subjectAltName types must be a valid URI";
305 56b1ed39 Phil Davis
						}
306 2f65de89 jim-p
						break;
307
					default:
308
						$input_errors[] = "Unrecognized subjectAltName type.";
309
				}
310
			}
311
312 21cc2faa Evgeny Yurchenko
			/* Make sure we do not have invalid characters in the fields for the certificate */
313 b741d2ef jim-p
314
			if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
315
				array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
316
			}
317
318 21cc2faa Evgeny Yurchenko
			for ($i = 0; $i < count($reqdfields); $i++) {
319 56b1ed39 Phil Davis
				if (preg_match('/email/', $reqdfields[$i])) { /* dn_email or csr_dn_name */
320
					if (preg_match("/[\!\#\$\%\^\(\)\~\?\>\<\&\/\\\,\"\']/", $_POST[$reqdfields[$i]])) {
321 21cc2faa Evgeny Yurchenko
						array_push($input_errors, "The field 'Distinguished name Email Address' contains invalid characters.");
322 56b1ed39 Phil Davis
					}
323
				} else if (preg_match('/commonname/', $reqdfields[$i])) { /* dn_commonname or csr_dn_commonname */
324
					if (preg_match("/[\!\@\#\$\%\^\(\)\~\?\>\<\&\/\\\,\"\']/", $_POST[$reqdfields[$i]])) {
325 21cc2faa Evgeny Yurchenko
						array_push($input_errors, "The field 'Distinguished name Common Name' contains invalid characters.");
326 56b1ed39 Phil Davis
					}
327
				} else if (($reqdfields[$i] != "descr") && preg_match("/[\!\@\#\$\%\^\(\)\~\?\>\<\&\/\\\,\.\"\']/", $_POST[$reqdfields[$i]])) {
328 21cc2faa Evgeny Yurchenko
					array_push($input_errors, "The field '" . $reqdfieldsn[$i] . "' contains invalid characters.");
329 56b1ed39 Phil Davis
				}
330 21cc2faa Evgeny Yurchenko
			}
331 738fab3d jim-p
332 56b1ed39 Phil Davis
			if (($pconfig['method'] != "external") && isset($_POST["keylen"]) && !in_array($_POST["keylen"], $cert_keylens)) {
333 741d748d jim-p
				array_push($input_errors, gettext("Please select a valid Key Length."));
334 56b1ed39 Phil Davis
			}
335
			if (($pconfig['method'] != "external") && !in_array($_POST["digest_alg"], $openssl_digest_algs)) {
336 8f07b51c PiBa-NL
				array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
337 56b1ed39 Phil Davis
			}
338 b49f31d0 Sjon Hortensius
339 56b1ed39 Phil Davis
			if (($pconfig['method'] == "external") && isset($_POST["csr_keylen"]) && !in_array($_POST["csr_keylen"], $cert_keylens)) {
340 ca621902 jim-p
				array_push($input_errors, gettext("Please select a valid Key Length."));
341 56b1ed39 Phil Davis
			}
342
			if (($pconfig['method'] == "external") && !in_array($_POST["csr_digest_alg"], $openssl_digest_algs)) {
343 ca621902 jim-p
				array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
344 56b1ed39 Phil Davis
			}
345 547c56c4 jim-p
		}
346 64cc39d3 Matthew Grooms
347
		/* if this is an AJAX caller then handle via JSON */
348
		if (isAjax() && is_array($input_errors)) {
349
			input_errors2Ajax($input_errors);
350
			exit;
351
		}
352
353
		/* save modifications */
354
		if (!$input_errors) {
355
356 ad9b5c67 jim-p
			if ($pconfig['method'] == "existing") {
357
				$cert = lookup_cert($pconfig['certref']);
358 56b1ed39 Phil Davis
				if ($cert && $a_user) {
359 ad9b5c67 jim-p
					$a_user[$userid]['cert'][] = $cert['refid'];
360 56b1ed39 Phil Davis
				}
361 ad9b5c67 jim-p
			} else {
362
				$cert = array();
363
				$cert['refid'] = uniqid();
364 56b1ed39 Phil Davis
				if (isset($id) && $a_cert[$id]) {
365 ad9b5c67 jim-p
					$cert = $a_cert[$id];
366 56b1ed39 Phil Davis
				}
367 ad9b5c67 jim-p
368 f2a86ca9 jim-p
				$cert['descr'] = $pconfig['descr'];
369 ad9b5c67 jim-p
370 f416763b Phil Davis
				$old_err_level = error_reporting(0); /* otherwise openssl_ functions throw warnings directly to a page screwing menu tab */
371 22b380aa Evgeny Yurchenko
372 56b1ed39 Phil Davis
				if ($pconfig['method'] == "import") {
373 ad9b5c67 jim-p
					cert_import($cert, $pconfig['cert'], $pconfig['key']);
374 56b1ed39 Phil Davis
				}
375 ad9b5c67 jim-p
376
				if ($pconfig['method'] == "internal") {
377
					$dn = array(
378
						'countryName' => $pconfig['dn_country'],
379
						'stateOrProvinceName' => $pconfig['dn_state'],
380
						'localityName' => $pconfig['dn_city'],
381
						'organizationName' => $pconfig['dn_organization'],
382
						'emailAddress' => $pconfig['dn_email'],
383
						'commonName' => $pconfig['dn_commonname']);
384 2f65de89 jim-p
					if (count($altnames)) {
385
						$altnames_tmp = "";
386
						foreach ($altnames as $altname) {
387
							$altnames_tmp[] = "{$altname['type']}:{$altname['value']}";
388
						}
389
						$dn['subjectAltName'] = implode(",", $altnames_tmp);
390
					}
391 22b380aa Evgeny Yurchenko
					if (!cert_create($cert, $pconfig['caref'], $pconfig['keylen'],
392 56b1ed39 Phil Davis
						$pconfig['lifetime'], $dn, $pconfig['type'], $pconfig['digest_alg'])) {
393
						while ($ssl_err = openssl_error_string()) {
394 22b380aa Evgeny Yurchenko
							$input_errors = array();
395
							array_push($input_errors, "openssl library returns: " . $ssl_err);
396
						}
397
					}
398 ad9b5c67 jim-p
				}
399
400
				if ($pconfig['method'] == "external") {
401
					$dn = array(
402
						'countryName' => $pconfig['csr_dn_country'],
403
						'stateOrProvinceName' => $pconfig['csr_dn_state'],
404
						'localityName' => $pconfig['csr_dn_city'],
405
						'organizationName' => $pconfig['csr_dn_organization'],
406
						'emailAddress' => $pconfig['csr_dn_email'],
407
						'commonName' => $pconfig['csr_dn_commonname']);
408 2f65de89 jim-p
					if (count($altnames)) {
409
						$altnames_tmp = "";
410
						foreach ($altnames as $altname) {
411
							$altnames_tmp[] = "{$altname['type']}:{$altname['value']}";
412
						}
413
						$dn['subjectAltName'] = implode(",", $altnames_tmp);
414
					}
415 56b1ed39 Phil Davis
					if (!csr_generate($cert, $pconfig['csr_keylen'], $dn, $pconfig['csr_digest_alg'])) {
416
						while ($ssl_err = openssl_error_string()) {
417 22b380aa Evgeny Yurchenko
							$input_errors = array();
418
							array_push($input_errors, "openssl library returns: " . $ssl_err);
419
						}
420
					}
421 ad9b5c67 jim-p
				}
422 22b380aa Evgeny Yurchenko
				error_reporting($old_err_level);
423
424 56b1ed39 Phil Davis
				if (isset($id) && $a_cert[$id]) {
425 ad9b5c67 jim-p
					$a_cert[$id] = $cert;
426 56b1ed39 Phil Davis
				} else {
427 ad9b5c67 jim-p
					$a_cert[] = $cert;
428 56b1ed39 Phil Davis
				}
429
				if (isset($a_user) && isset($userid)) {
430 ad9b5c67 jim-p
					$a_user[$userid]['cert'][] = $cert['refid'];
431 56b1ed39 Phil Davis
				}
432 64cc39d3 Matthew Grooms
			}
433
434 56b1ed39 Phil Davis
			if (!$input_errors) {
435 22b380aa Evgeny Yurchenko
				write_config();
436 56b1ed39 Phil Davis
			}
437 64cc39d3 Matthew Grooms
438 1a6769a6 Renato Botelho
			if ($userid) {
439
				post_redirect("system_usermanager.php", array('act' => 'edit', 'userid' => $userid));
440
				exit;
441
			}
442 64cc39d3 Matthew Grooms
		}
443
	}
444
445 a37753d7 Vinicius Coque
	if ($_POST['save'] == gettext("Update")) {
446 64cc39d3 Matthew Grooms
		unset($input_errors);
447
		$pconfig = $_POST;
448
449
		/* input validation */
450 5293bfec jim-p
		$reqdfields = explode(" ", "descr cert");
451 76d49f20 Renato Botelho
		$reqdfieldsn = array(
452 56b1ed39 Phil Davis
		gettext("Descriptive name"),
453
		gettext("Final Certificate data"));
454 64cc39d3 Matthew Grooms
455 1e9b4611 Renato Botelho
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
456 64cc39d3 Matthew Grooms
457 b741d2ef jim-p
		if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
458
			array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
459
		}
460
461 a828210b yakatz
//		old way
462 64cc39d3 Matthew Grooms
		/* make sure this csr and certificate subjects match */
463 a828210b yakatz
//		$subj_csr = csr_get_subject($pconfig['csr'], false);
464
//		$subj_cert = cert_get_subject($pconfig['cert'], false);
465
//
466 56b1ed39 Phil Davis
//		if (!isset($_POST['ignoresubjectmismatch']) && !($_POST['ignoresubjectmismatch'] == "yes")) {
467
//			if (strcmp($subj_csr, $subj_cert)) {
468
//				$input_errors[] = sprintf(gettext("The certificate subject '%s' does not match the signing request subject."), $subj_cert);
469 a828210b yakatz
//				$subject_mismatch = true;
470
//			}
471
//		}
472 6c07db48 Phil Davis
		$mod_csr = csr_get_modulus($pconfig['csr'], false);
473 2594f401 yakatz
		$mod_cert = cert_get_modulus($pconfig['cert'], false);
474 b49f31d0 Sjon Hortensius
475 56b1ed39 Phil Davis
		if (strcmp($mod_csr, $mod_cert)) {
476 a828210b yakatz
			// simply: if the moduli don't match, then the private key and public key won't match
477 56b1ed39 Phil Davis
			$input_errors[] = sprintf(gettext("The certificate modulus does not match the signing request modulus."), $subj_cert);
478 a828210b yakatz
			$subject_mismatch = true;
479
		}
480 64cc39d3 Matthew Grooms
481
		/* if this is an AJAX caller then handle via JSON */
482
		if (isAjax() && is_array($input_errors)) {
483
			input_errors2Ajax($input_errors);
484
			exit;
485
		}
486
487
		/* save modifications */
488
		if (!$input_errors) {
489
490
			$cert = $a_cert[$id];
491
492 f2a86ca9 jim-p
			$cert['descr'] = $pconfig['descr'];
493 64cc39d3 Matthew Grooms
494
			csr_complete($cert, $pconfig['cert']);
495
496
			$a_cert[$id] = $cert;
497
498
			write_config();
499
500
			pfSenseHeader("system_certmanager.php");
501
		}
502
	}
503
}
504
505
include("head.inc");
506 b49f31d0 Sjon Hortensius
507
if ($input_errors)
508
	print_input_errors($input_errors);
509
if ($savemsg)
510
	print_info_box($savemsg);
511
512
$tab_array = array();
513
$tab_array[] = array(gettext("CAs"), false, "system_camanager.php");
514
$tab_array[] = array(gettext("Certificates"), true, "system_certmanager.php");
515
$tab_array[] = array(gettext("Certificate Revocation"), false, "system_crlmanager.php");
516
display_top_tabs($tab_array);
517
518
// Load valid country codes
519
$dn_cc = array();
520
if (file_exists("/etc/ca_countries")){
521
	$dn_cc_file=file("/etc/ca_countries");
522 b8f22f61 Stephen Beaver
	foreach($dn_cc_file as $line) {
523
		if (preg_match('/^(\S*)\s(.*)$/', $line, $matches)) {
524
			$dn_cc[$matches[1]] = $matches[1];
525
		}
526
	}
527 b49f31d0 Sjon Hortensius
}
528
529
if (!($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)))
530
{
531 64cc39d3 Matthew Grooms
?>
532 b49f31d0 Sjon Hortensius
<div class="table-responsive">
533
<table class="table table-striped table-hover">
534
	<thead>
535
		<tr>
536
			<th><?=gettext("Name")?></th>
537
			<th><?=gettext("Issuer")?></th>
538
			<th><?=gettext("Distinguished Name")?></th>
539
			<th><?=gettext("In Use")?></th>
540
			<th></th>
541
		</tr>
542
	</thead>
543
	<tbody>
544
<?php
545
foreach($a_cert as $i => $cert):
546
	$name = htmlspecialchars($cert['descr']);
547 64cc39d3 Matthew Grooms
548 b49f31d0 Sjon Hortensius
	if ($cert['crt']) {
549
		$subj = cert_get_subject($cert['crt']);
550
		$issuer = cert_get_issuer($cert['crt']);
551
		$purpose = cert_get_purpose($cert['crt']);
552
		list($startdate, $enddate) = cert_get_dates($cert['crt']);
553 64cc39d3 Matthew Grooms
554 b49f31d0 Sjon Hortensius
		if ($subj==$issuer)
555
			$caname = '<i>'. gettext("self-signed") .'</i>';
556
		else
557
			$caname = '<i>'. gettext("external").'</i>';
558 64cc39d3 Matthew Grooms
559 b49f31d0 Sjon Hortensius
		$subj = htmlspecialchars($subj);
560
	}
561
562
	if ($cert['csr']) {
563
		$subj = htmlspecialchars(csr_get_subject($cert['csr']));
564
		$caname = "<em>" . gettext("external - signature pending") . "</em>";
565
	}
566
567
	$ca = lookup_ca($cert['caref']);
568
	if ($ca)
569
		$caname = $ca['descr'];
570 64cc39d3 Matthew Grooms
?>
571 b49f31d0 Sjon Hortensius
		<tr>
572
			<td>
573
				<?=$name?>
574
				<?php if ($cert['type']): ?>
575
					<i><?=$cert_types[$cert['type']]?></i>
576
				<?php endif?>
577
				<?php if (is_array($purpose)): ?>
578
					CA: <b><?=$purpose['ca']?></b>, Server: <b><?=$purpose['server']?></b>
579
				<?php endif?>
580
			</td>
581
			<td><?=$caname?></td>
582
			<td>
583
				<?=$subj?>
584
				<br />
585
				<small>
586 b8f22f61 Stephen Beaver
					<?=gettext("Valid From")?>: <b><?=$startdate ?></b><br /><?=gettext("Valid Until")?>: <b><?=$enddate ?></b>
587 b49f31d0 Sjon Hortensius
				</small>
588
			</td>
589
			<td>
590
				<?php if (is_cert_revoked($cert)): ?>
591
					<i>Revoked </i>
592
				<?php endif?>
593
				<?php if (is_webgui_cert($cert['refid'])): ?>
594
					webConfigurator
595
				<?php endif?>
596
				<?php if (is_user_cert($cert['refid'])): ?>
597
					User Cert
598
				<?php endif?>
599
				<?php if (is_openvpn_server_cert($cert['refid'])): ?>
600
					OpenVPN Server
601
				<?php endif?>
602
				<?php if (is_openvpn_client_cert($cert['refid'])): ?>
603
					OpenVPN Client
604
				<?php endif?>
605
				<?php if (is_ipsec_cert($cert['refid'])): ?>
606
					IPsec Tunnel
607
				<?php endif?>
608
				<?php if (is_captiveportal_cert($cert['refid'])): ?>
609
					Captive Portal
610
				<?php endif?>
611
			</td>
612
			<td>
613
				<a href="system_certmanager.php?act=exp&amp;id=<?=$i?>" class="btn btn-xs btn-default">
614
					<?=gettext("export")?>
615
				</a>
616
				<a href="system_certmanager.php?act=key&amp;id=<?=$i?>" class="btn btn-xs btn-default">
617
					<?=gettext("export key")?>
618
				</a>
619
				<a href="system_certmanager.php?act=p12&amp;id=<?=$i?>" class="btn btn-xs btn-default">
620
					<?=gettext("export p12")?>
621
				</a>
622
				<?php if (!cert_in_use($cert['refid'])): ?>
623
					<a href="system_certmanager.php?act=del&amp;id=<?=$i?>" class="btn btn-xs btn-danger">
624
						<?=gettext("delete")?>
625
					</a>
626
				<?php endif?>
627
				<?php if ($cert['csr']): ?>
628
					<a href="system_certmanager.php?act=csr&amp;id=<?=$i?>" class="btn btn-xs btn-default">
629
						<?=gettext("update csr")?>
630
					</a>
631
				<?php endif?>
632
			</td>
633
		</tr>
634
<?php endforeach; ?>
635
	</tbody>
636
</table>
637
</div>
638
639
<nav class="action-buttons">
640
	<a href="?act=new" class="btn btn-success">add new</a>
641
</nav>
642
<?
643
	include("foot.inc");
644
	exit;
645
}
646 64cc39d3 Matthew Grooms
647 b49f31d0 Sjon Hortensius
require('classes/Form.class.php');
648
$form = new Form;
649
650
if ($act == "csr" || (($_POST['save'] == gettext("Update")) && $input_errors))
651
{
652
	$form->setAction('system_certmanager.php?act=csr');
653
654
	$section = new Form_Section('Complete Signing Request');
655
656
	if (isset($id) && $a_cert[$id])
657
	{
658
		$form->addGlobal(new Form_Input(
659
			'id',
660
			null,
661
			'hidden',
662
			$id
663
		));
664 64cc39d3 Matthew Grooms
	}
665 b49f31d0 Sjon Hortensius
666
	$section->addInput(new Form_Input(
667
		'descr',
668
		'Descriptive name',
669
		'text',
670
		$pconfig['descr']
671
	));
672
673
	$section->addInput(new Form_Textarea(
674
		'csr',
675
		'Signing request data',
676
		$pconfig['csr']
677
	))->setReadonly()->setHelp('Copy the certificate signing data from here and '.
678
		'forward it to your certificate authority for signing.');
679
680
	$section->addInput(new Form_Textarea(
681
		'cert',
682
		'Final certificate data',
683
		$pconfig["cert"]
684
	))->setHelp('Paste the certificate received from your certificate authority here.');
685
686
	$form->add($section);
687
	print $form;
688
689
	include("foot.inc");
690
	exit;
691 64cc39d3 Matthew Grooms
}
692
693 b49f31d0 Sjon Hortensius
$form->setAction('system_certmanager.php?act=edit');
694 64cc39d3 Matthew Grooms
695 b49f31d0 Sjon Hortensius
if (isset($userid) && $a_user)
696
{
697
	$form->addGlobal(new Form_Input(
698
		'userid',
699
		null,
700
		'hidden',
701
		$userid
702
	));
703
}
704 64cc39d3 Matthew Grooms
705 b49f31d0 Sjon Hortensius
if (isset($id) && $a_cert[$id])
706
{
707
	$form->addGlobal(new Form_Input(
708
		'id',
709
		null,
710
		'hidden',
711
		$id
712
	));
713
}
714
715
$section = new Form_Section('Add a new certificate');
716
717
if (!isset($id))
718
{
719
	$section->addInput(new Form_Select(
720
		'method',
721
		'Method',
722
		$pconfig['method'],
723
		$cert_methods
724 44d906ca Sjon Hortensius
	))->toggles();
725 b49f31d0 Sjon Hortensius
}
726
727
$section->addInput(new Form_Input(
728
	'descr',
729
	'Descriptive name',
730
	'text',
731
	($a_user && empty($pconfig['descr'])) ? $a_user[$userid]['name'] : $pconfig['descr']
732
))->addClass('toggle-existing');
733
734
$form->add($section);
735
$section = new Form_Section('Import Certificate');
736
$section->addClass('toggle-import collapse');
737
738
$section->addInput(new Form_Textarea(
739
	'cert',
740
	'Certificate data',
741
	$pconfig['cert']
742
))->setHelp('Paste a certificate in X.509 PEM format here.');
743
744
$section->addInput(new Form_Textarea(
745
	'key',
746
	'Private key data',
747
	$pconfig['key']
748
))->setHelp('Paste a private key in X.509 PEM format here.');
749
750
$form->add($section);
751
$section = new Form_Section('Internal Certificate');
752
$section->addClass('toggle-internal collapse');
753
754
if (!$internal_ca_count)
755
{
756
	$section->addInput(new Form_StaticText(
757
		'Certificate authority',
758 8b35eae5 Stephen Beaver
		gettext('No internal Certificate Authorities have been defined. You must ').
759 1391193e Stephen Beaver
		'<a href="system_camanager.php?act=new&amp;method=internal"> '. gettext(" create") .'</a>'.
760
		gettext(' an internal CA before creating an internal certificate.')
761 b49f31d0 Sjon Hortensius
	));
762
}
763
else
764
{
765
	$allCas = array();
766
	foreach ($a_ca as $ca)
767
	{
768
		if (!$ca['prv'])
769 64cc39d3 Matthew Grooms
				continue;
770 b49f31d0 Sjon Hortensius
771
		$allCas[ $ca['refid'] ] = $ca['descr'];
772 64cc39d3 Matthew Grooms
	}
773 b49f31d0 Sjon Hortensius
774
	$section->addInput(new Form_Select(
775
		'caref',
776
		'Certificate authority',
777
		$pconfig['caref'],
778
		$allCas
779
	));
780 64cc39d3 Matthew Grooms
}
781
782 b49f31d0 Sjon Hortensius
$section->addInput(new Form_Select(
783
	'keylen',
784
	'Key length',
785
	$pconfig['keylen'],
786 8b35eae5 Stephen Beaver
	array_combine($cert_keylens, $cert_keylens)
787 b49f31d0 Sjon Hortensius
));
788
789
$section->addInput(new Form_Select(
790
	'digest_alg',
791
	'Digest Algorithm',
792
	$pconfig['digest_alg'],
793 8b35eae5 Stephen Beaver
	array_combine($openssl_digest_algs, $openssl_digest_algs)
794 b49f31d0 Sjon Hortensius
))->setHelp('NOTE: It is recommended to use an algorithm stronger than '.
795 1391193e Stephen Beaver
	'SHA1 when possible.');
796 b49f31d0 Sjon Hortensius
797
$section->addInput(new Form_Select(
798
	'type',
799
	'Certificate Type',
800
	$pconfig['type'],
801
	$cert_types
802
))->setHelp('Type of certificate to generate. Used for placing '.
803
	'restrictions on the usage of the generated certificate.');
804
805
$section->addInput(new Form_Input(
806
	'lifetime',
807
	'Lifetime (days)',
808
	'number',
809
	$pconfig['lifetime']
810
));
811
812
$section->addInput(new Form_Select(
813
	'dn_country',
814
	'Country Code',
815
	$pconfig['dn_country'],
816
	$dn_cc
817
));
818
819
$section->addInput(new Form_Input(
820
	'dn_state',
821
	'State or Province',
822
	'text',
823
	$pconfig['dn_state'],
824
	['placeholder' => 'e.g. Texas']
825
));
826
827
$section->addInput(new Form_Input(
828
	'dn_city',
829
	'City',
830
	'text',
831
	$pconfig['dn_city'],
832
	['placeholder' => 'e.g. Austin']
833
));
834
835
$section->addInput(new Form_Input(
836
	'dn_organization',
837
	'Organization',
838
	'text',
839
	$pconfig['dn_organization'],
840
	['placeholder' => 'e.g. My Company Inc.']
841
));
842
843
$section->addInput(new Form_Input(
844
	'dn_email',
845
	'Email Address',
846
	'email',
847
	$pconfig['dn_email'],
848
	['placeholder' => 'e.g. admin@mycompany.com']
849
));
850
851
$section->addInput(new Form_Input(
852
	'dn_commonname',
853
	'Common Name',
854
	'text',
855
	$pconfig['dn_commonname'],
856
	['placeholder' => 'e.g. internal-ca']
857
));
858
859
$group = new Form_Group('Alternative Names');
860
861
if (empty($pconfig['altnames']['item']))
862
{
863
	$pconfig['altnames']['item'] = array(
864
		array('type' => null, 'value' => null)
865
	);
866
}
867
868
foreach ($pconfig['altnames']['item'] as $item)
869
{
870
	$group->add(new Form_Select(
871
		'altname_type',
872
		'Type',
873
		$item['type'],
874
		array(
875
			'DNS' => 'FQDN or Hostname',
876
			'IP' => 'IP address',
877
			'URI' => 'URI',
878
			'email' => 'email address',
879
		)
880
	));
881
882
	$group->add(new Form_Input(
883
		'altname_value',
884
		'Type',
885
		'text',
886
		$item['value']
887
	));
888
889
	$group->enableDuplication();
890
}
891
892
$section->add($group);
893
894
$form->add($section);
895
$section = new Form_Section('External Signing Request');
896
$section->addClass('toggle-external collapse');
897
898
$section->addInput(new Form_Select(
899
	'csr_keylen',
900
	'Key length',
901
	$pconfig['csr_keylen'],
902
	$cert_keylens
903
));
904
905
$section->addInput(new Form_Select(
906
	'csr_digest_alg',
907
	'Digest Algorithm',
908
	$pconfig['csr_digest_alg'],
909
	$openssl_digest_algs
910
))->setHelp('NOTE: It is recommended to use an algorithm stronger than '.
911
	'SHA1 when possible');
912
913
$section->addInput(new Form_Select(
914
	'dn_country',
915
	'Country Code',
916
	$pconfig['dn_country'],
917
	$dn_cc
918
));
919
920
$section->addInput(new Form_Input(
921
	'csr_dn_state',
922
	'State or Province',
923
	'text',
924
	$pconfig['csr_dn_state'],
925
	['placeholder' => 'e.g. Texas']
926
));
927
928
$section->addInput(new Form_Input(
929
	'csr_dn_city',
930
	'City',
931
	'text',
932
	$pconfig['csr_dn_city'],
933
	['placeholder' => 'e.g. Austin']
934
));
935
936
$section->addInput(new Form_Input(
937
	'csr_dn_organization',
938
	'Organization',
939
	'text',
940
	$pconfig['csr_dn_organization'],
941
	['placeholder' => 'e.g. My Company Inc.']
942
));
943
944
$section->addInput(new Form_Input(
945
	'csr_dn_email',
946
	'Email Address',
947
	'email',
948
	$pconfig['csr_dn_email'],
949
	['placeholder' => 'e.g. admin@mycompany.com']
950
));
951
952
$section->addInput(new Form_Input(
953
	'csr_dn_commonname',
954
	'Common Name',
955
	'text',
956
	$pconfig['csr_dn_commonname'],
957
	['placeholder' => 'e.g. internal-ca']
958
));
959
960
$form->add($section);
961
$section = new Form_Section('Choose an Existing Certificate');
962
$section->addClass('toggle-existing collapse');
963
964
$existCerts = array();
965
foreach ($config['cert'] as $cert)
966
{
967
	if (isset($userid) && in_array($cert['refid'], $config['system']['user'][$userid]['cert']))
968
		continue;
969
970
	$ca = lookup_ca($cert['caref']);
971
	if ($ca)
972
		$cert['descr'] .= " (CA: {$ca['descr']})";
973
974
	if (cert_in_use($cert['refid']))
975
		$cert['descr'] .= " <i>In Use</i>";
976
	if (is_cert_revoked($cert))
977
		$cert['descr'] .= " <b>Revoked</b>";
978
979
	$existCerts[ $cert['refid'] ] = $cert['descr'];
980
}
981
982
$section->addInput(new Form_Select(
983
	'certref',
984
	'Existing Certificates',
985
	$pconfig['certref'],
986
	$existCerts
987
));
988
989
$form->add($section);
990
print $form;
991 64cc39d3 Matthew Grooms
992 51583438 Stephen Beaver
?>
993
<script>
994
//<![CDATA[
995
events.push(function(){
996
<?php if ($internal_ca_count): ?>
997
	function internalca_change() {
998
999
		caref = $('#caref').val();
1000
1001
		switch (caref) {
1002
<?php
1003
			foreach ($a_ca as $ca):
1004
				if (!$ca['prv']) {
1005
					continue;
1006
				}
1007
1008
				$subject = cert_get_subject_array($ca['crt']);
1009
1010
?>
1011
				case "<?=$ca['refid'];?>":
1012
					$('#dn_country').val("<?=$subject[0]['v'];?>");
1013
					$('#dn_state').val("<?=$subject[1]['v'];?>");
1014
					$('#dn_city').val("<?=$subject[2]['v'];?>");
1015
					$('#dn_organization').val("<?=$subject[3]['v'];?>");
1016
					$('#dn_email').val("<?=$subject[4]['v'];?>");
1017
					break;
1018
<?php
1019
			endforeach;
1020
?>
1021
		}
1022
	}
1023
1024
	// On click . .
1025
	$('#caref').on('change', function() {
1026
		internalca_change();
1027
	});
1028
1029
	// On page load . .
1030
	internalca_change();
1031
1032
<?php endif; ?>
1033
1034
1035
});
1036
//]]>
1037
</script>
1038
<?php
1039 1391193e Stephen Beaver
include('foot.inc');