Project

General

Profile

Download (25.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * system_camanager.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2020 Rubicon Communications, LLC (Netgate)
9
 * Copyright (c) 2008 Shrew Soft Inc
10
 * All rights reserved.
11
 *
12
 * 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
 *
16
 * http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * 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
 */
24

    
25
##|+PRIV
26
##|*IDENT=page-system-camanager
27
##|*NAME=System: CA Manager
28
##|*DESCR=Allow access to the 'System: CA Manager' page.
29
##|*MATCH=system_camanager.php*
30
##|-PRIV
31

    
32
require_once("guiconfig.inc");
33
require_once("certs.inc");
34
require_once("pfsense-utils.inc");
35

    
36
$ca_methods = array(
37
	"internal" => gettext("Create an internal Certificate Authority"),
38
	"existing" => gettext("Import an existing Certificate Authority"),
39
	"intermediate" => gettext("Create an intermediate Certificate Authority"));
40

    
41
$ca_keylens = array("1024", "2048", "3072", "4096", "6144", "7680", "8192", "15360", "16384");
42
$ca_keytypes = array("RSA", "ECDSA");
43
global $openssl_digest_algs;
44
global $cert_strict_values;
45
$max_lifetime = cert_get_max_lifetime();
46
$default_lifetime = min(3650, $max_lifetime);
47
$openssl_ecnames = cert_build_curve_list();
48
$class = "success";
49

    
50
init_config_arr(array('ca'));
51
$a_ca = &$config['ca'];
52

    
53
init_config_arr(array('cert'));
54
$a_cert = &$config['cert'];
55

    
56
init_config_arr(array('crl'));
57
$a_crl = &$config['crl'];
58

    
59
$act = $_REQUEST['act'];
60

    
61
if (isset($_REQUEST['id']) && ctype_alnum($_REQUEST['id'])) {
62
	$id = $_REQUEST['id'];
63
}
64
if (!empty($id)) {
65
	$thisca =& lookup_ca($id);
66
}
67

    
68
/* Actions other than 'new' require an ID.
69
 * 'del' action must be submitted via POST. */
70
if ((!empty($act) &&
71
    ($act != 'new') &&
72
    !$thisca) ||
73
    (($act == 'del') && empty($_POST))) {
74
	pfSenseHeader("system_camanager.php");
75
	exit;
76
}
77

    
78
switch ($act) {
79
	case 'del':
80
		$name = htmlspecialchars($thisca['descr']);
81
		if (cert_in_use($id)) {
82
			$savemsg = sprintf(gettext("Certificate %s is in use and cannot be deleted"), $name);
83
			$class = "danger";
84
		} else {
85
			/* Only remove CA reference when deleting. It can be reconnected if a new matching CA is imported */
86
			foreach ($a_cert as $cid => $acrt) {
87
				if ($acrt['caref'] == $thisca['refid']) {
88
					unset($a_cert[$cid]['caref']);
89
				}
90
			}
91
			/* Remove any CRLs for this CA, there is no way to recover the connection once the CA has been removed. */
92
			foreach ($a_crl as $cid => $acrl) {
93
				if ($acrl['caref'] == $thisca['refid']) {
94
					unset($a_crl[$cid]);
95
				}
96
			}
97
			/* Delete the CA */
98
			foreach ($a_ca as $cid => $aca) {
99
				if ($aca['refid'] == $thisca['refid']) {
100
					unset($a_ca[$cid]);
101
				}
102
			}
103
			$savemsg = sprintf(gettext("Deleted Certificate Authority %s and associated CRLs"), htmlspecialchars($name));
104
			write_config($savemsg);
105
			ca_setup_trust_store();
106
		}
107
		unset($act);
108
		break;
109
	case 'edit':
110
		/* Editing an existing CA, so populate values. */
111
		$pconfig['method'] = 'existing';
112
		$pconfig['descr']  = $thisca['descr'];
113
		$pconfig['refid']  = $thisca['refid'];
114
		$pconfig['cert']   = base64_decode($thisca['crt']);
115
		$pconfig['serial'] = $thisca['serial'];
116
		$pconfig['trust']  = ($thisca['trust'] == 'enabled');
117
		$pconfig['randomserial']  = ($thisca['randomserial'] == 'enabled');
118
		if (!empty($thisca['prv'])) {
119
			$pconfig['key'] = base64_decode($thisca['prv']);
120
		}
121
		break;
122
	case 'new':
123
		/* New CA, so set default values */
124
		$pconfig['method'] = $_POST['method'];
125
		$pconfig['keytype'] = "RSA";
126
		$pconfig['keylen'] = "2048";
127
		$pconfig['ecname'] = "prime256v1";
128
		$pconfig['digest_alg'] = "sha256";
129
		$pconfig['lifetime'] = $default_lifetime;
130
		$pconfig['dn_commonname'] = "internal-ca";
131
		break;
132
	case 'exp':
133
		/* Exporting a ca */
134
		send_user_download('data', base64_decode($thisca['crt']), "{$thisca['descr']}.crt");
135
		break;
136
	case 'expkey':
137
		/* Exporting a private key */
138
		send_user_download('data', base64_decode($thisca['prv']), "{$thisca['descr']}.key");
139
		break;
140
	default:
141
		break;
142
}
143

    
144
if ($_POST['save']) {
145
	unset($input_errors);
146
	$input_errors = array();
147
	$pconfig = $_POST;
148

    
149
	/* input validation */
150
	switch ($pconfig['method']) {
151
		case 'existing':
152
			$reqdfields = explode(" ", "descr cert");
153
			$reqdfieldsn = array(
154
				gettext("Descriptive name"),
155
				gettext("Certificate data"));
156
			if ($_POST['cert'] && (!strstr($_POST['cert'], "BEGIN CERTIFICATE") || !strstr($_POST['cert'], "END CERTIFICATE"))) {
157
				$input_errors[] = gettext("This certificate does not appear to be valid.");
158
			}
159
			if ($_POST['key'] && strstr($_POST['key'], "ENCRYPTED")) {
160
				$input_errors[] = gettext("Encrypted private keys are not yet supported.");
161
			}
162
			if (!$input_errors && !empty($_POST['key']) && cert_get_publickey($_POST['cert'], false) != cert_get_publickey($_POST['key'], false, 'prv')) {
163
				$input_errors[] = gettext("The submitted private key does not match the submitted certificate data.");
164
			}
165
			/* we must ensure the certificate is capable of acting as a CA
166
			 * https://redmine.pfsense.org/issues/7885
167
			 */
168
			if (!$input_errors) {
169
				$purpose = cert_get_purpose($_POST['cert'], false);
170
				if ($purpose['ca'] != 'Yes') {
171
					$input_errors[] = gettext("The submitted certificate does not appear to be a Certificate Authority, import it on the Certificates tab instead.");
172
				}
173
			}
174
			break;
175
		case 'internal':
176
			$reqdfields = explode(" ",
177
				"descr keylen ecname keytype lifetime dn_commonname");
178
			$reqdfieldsn = array(
179
				gettext("Descriptive name"),
180
				gettext("Key length"),
181
				gettext("Elliptic Curve Name"),
182
				gettext("Key type"),
183
				gettext("Lifetime"),
184
				gettext("Common Name"));
185
			break;
186
		case 'intermediate':
187
			$reqdfields = explode(" ",
188
				"descr caref keylen ecname keytype lifetime dn_commonname");
189
			$reqdfieldsn = array(
190
				gettext("Descriptive name"),
191
				gettext("Signing Certificate Authority"),
192
				gettext("Key length"),
193
				gettext("Elliptic Curve Name"),
194
				gettext("Key type"),
195
				gettext("Lifetime"),
196
				gettext("Common Name"));
197
			break;
198
		default:
199
			break;
200
	}
201

    
202
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
203
	if ($pconfig['method'] != "existing") {
204
		/* Make sure we do not have invalid characters in the fields for the certificate */
205
		if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
206
			array_push($input_errors, gettext("The field 'Descriptive Name' contains invalid characters."));
207
		}
208
		if (!in_array($_POST["keytype"], $ca_keytypes)) {
209
			array_push($input_errors, gettext("Please select a valid Key Type."));
210
		}
211
		if (!in_array($_POST["keylen"], $ca_keylens)) {
212
			array_push($input_errors, gettext("Please select a valid Key Length."));
213
		}
214
		if (!in_array($_POST["ecname"], array_keys($openssl_ecnames))) {
215
			array_push($input_errors, gettext("Please select a valid Elliptic Curve Name."));
216
		}
217
		if (!in_array($_POST["digest_alg"], $openssl_digest_algs)) {
218
			array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
219
		}
220
		if ($_POST['lifetime'] > $max_lifetime) {
221
			$input_errors[] = gettext("Lifetime is longer than the maximum allowed value. Use a shorter lifetime.");
222
		}
223
	}
224

    
225
	if (!empty($_POST['serial']) && !cert_validate_serial($_POST['serial'])) {
226
		$input_errors[] = gettext("Please enter a valid integer serial number.");
227
	}
228

    
229
	/* save modifications */
230
	if (!$input_errors) {
231
		$ca = array();
232
		if (!isset($pconfig['refid']) || empty($pconfig['refid'])) {
233
			$ca['refid'] = uniqid();
234
		} else {
235
			$ca['refid'] = $pconfig['refid'];
236
		}
237

    
238
		if (isset($id) && $thisca) {
239
			$ca = $thisca;
240
		}
241

    
242
		$ca['descr'] = $pconfig['descr'];
243
		$ca['trust'] = ($pconfig['trust'] == 'yes') ? "enabled" : "disabled";
244
		$ca['randomserial'] = ($pconfig['randomserial'] == 'yes') ? "enabled" : "disabled";
245

    
246
		if ($act == "edit") {
247
			$ca['descr']  = $pconfig['descr'];
248
			$ca['refid']  = $pconfig['refid'];
249
			$ca['serial'] = $pconfig['serial'];
250
			$ca['crt']	  = base64_encode($pconfig['cert']);
251
			if (!empty($pconfig['key'])) {
252
				$ca['prv']	  = base64_encode($pconfig['key']);
253
			}
254
			$savemsg = sprintf(gettext("Updated Certificate Authority %s"), $ca['descr']);
255
		} else {
256
			$old_err_level = error_reporting(0); /* otherwise openssl_ functions throw warnings directly to a page screwing menu tab */
257
			if ($pconfig['method'] == "existing") {
258
				ca_import($ca, $pconfig['cert'], $pconfig['key'], $pconfig['serial']);
259
				$savemsg = sprintf(gettext("Imported Certificate Authority %s"), $ca['descr']);
260
			} else if ($pconfig['method'] == "internal") {
261
				$dn = array('commonName' => cert_escape_x509_chars($pconfig['dn_commonname']));
262
				if (!empty($pconfig['dn_country'])) {
263
					$dn['countryName'] = $pconfig['dn_country'];
264
				}
265
				if (!empty($pconfig['dn_state'])) {
266
					$dn['stateOrProvinceName'] = cert_escape_x509_chars($pconfig['dn_state']);
267
				}
268
				if (!empty($pconfig['dn_city'])) {
269
					$dn['localityName'] = cert_escape_x509_chars($pconfig['dn_city']);
270
				}
271
				if (!empty($pconfig['dn_organization'])) {
272
					$dn['organizationName'] = cert_escape_x509_chars($pconfig['dn_organization']);
273
				}
274
				if (!empty($pconfig['dn_organizationalunit'])) {
275
					$dn['organizationalUnitName'] = cert_escape_x509_chars($pconfig['dn_organizationalunit']);
276
				}
277
				if (!ca_create($ca, $pconfig['keylen'], $pconfig['lifetime'], $dn, $pconfig['digest_alg'], $pconfig['keytype'], $pconfig['ecname'])) {
278
					$input_errors = array();
279
					while ($ssl_err = openssl_error_string()) {
280
						if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
281
							array_push($input_errors, "openssl library returns: " . $ssl_err);
282
						}
283
					}
284
				}
285
				$savemsg = sprintf(gettext("Created internal Certificate Authority %s"), $ca['descr']);
286
			} else if ($pconfig['method'] == "intermediate") {
287
				$dn = array('commonName' => cert_escape_x509_chars($pconfig['dn_commonname']));
288
				if (!empty($pconfig['dn_country'])) {
289
					$dn['countryName'] = $pconfig['dn_country'];
290
				}
291
				if (!empty($pconfig['dn_state'])) {
292
					$dn['stateOrProvinceName'] = cert_escape_x509_chars($pconfig['dn_state']);
293
				}
294
				if (!empty($pconfig['dn_city'])) {
295
					$dn['localityName'] = cert_escape_x509_chars($pconfig['dn_city']);
296
				}
297
				if (!empty($pconfig['dn_organization'])) {
298
					$dn['organizationName'] = cert_escape_x509_chars($pconfig['dn_organization']);
299
				}
300
				if (!empty($pconfig['dn_organizationalunit'])) {
301
					$dn['organizationalUnitName'] = cert_escape_x509_chars($pconfig['dn_organizationalunit']);
302
				}
303
				if (!ca_inter_create($ca, $pconfig['keylen'], $pconfig['lifetime'], $dn, $pconfig['caref'], $pconfig['digest_alg'], $pconfig['keytype'], $pconfig['ecname'])) {
304
					$input_errors = array();
305
					while ($ssl_err = openssl_error_string()) {
306
						if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
307
							array_push($input_errors, "openssl library returns: " . $ssl_err);
308
						}
309
					}
310
				}
311
				$savemsg = sprintf(gettext("Created internal intermediate Certificate Authority %s"), $ca['descr']);
312
			}
313
			error_reporting($old_err_level);
314
		}
315

    
316
		if (isset($id) && $thisca) {
317
			$thisca = $ca;
318
		} else {
319
			$a_ca[] = $ca;
320
		}
321

    
322
		if (!$input_errors) {
323
			write_config($savemsg);
324
			ca_setup_trust_store();
325
			pfSenseHeader("system_camanager.php");
326
		}
327
	}
328
}
329

    
330
$pgtitle = array(gettext("System"), gettext("Certificate Manager"), gettext("CAs"));
331
$pglinks = array("", "system_camanager.php", "system_camanager.php");
332

    
333
if ($act == "new" || $act == "edit" || $act == gettext("Save") || $input_errors) {
334
	$pgtitle[] = gettext('Edit');
335
	$pglinks[] = "@self";
336
}
337
include("head.inc");
338

    
339
if ($input_errors) {
340
	print_input_errors($input_errors);
341
}
342

    
343
if ($savemsg) {
344
	print_info_box($savemsg, $class);
345
}
346

    
347
$tab_array = array();
348
$tab_array[] = array(gettext("CAs"), true, "system_camanager.php");
349
$tab_array[] = array(gettext("Certificates"), false, "system_certmanager.php");
350
$tab_array[] = array(gettext("Certificate Revocation"), false, "system_crlmanager.php");
351
display_top_tabs($tab_array);
352

    
353
if (!($act == "new" || $act == "edit" || $act == gettext("Save") || $input_errors)) {
354
?>
355
<div class="panel panel-default" id="search-panel">
356
	<div class="panel-heading">
357
		<h2 class="panel-title">
358
			<?=gettext('Search')?>
359
			<span class="widget-heading-icon pull-right">
360
				<a data-toggle="collapse" href="#search-panel_panel-body">
361
					<i class="fa fa-plus-circle"></i>
362
				</a>
363
			</span>
364
		</h2>
365
	</div>
366
	<div id="search-panel_panel-body" class="panel-body collapse in">
367
		<div class="form-group">
368
			<label class="col-sm-2 control-label">
369
				<?=gettext("Search term")?>
370
			</label>
371
			<div class="col-sm-5"><input class="form-control" name="searchstr" id="searchstr" type="text"/></div>
372
			<div class="col-sm-2">
373
				<select id="where" class="form-control">
374
					<option value="0"><?=gettext("Name")?></option>
375
					<option value="1"><?=gettext("Distinguished Name")?></option>
376
					<option value="2" selected><?=gettext("Both")?></option>
377
				</select>
378
			</div>
379
			<div class="col-sm-3">
380
				<a id="btnsearch" title="<?=gettext("Search")?>" class="btn btn-primary btn-sm"><i class="fa fa-search icon-embed-btn"></i><?=gettext("Search")?></a>
381
				<a id="btnclear" title="<?=gettext("Clear")?>" class="btn btn-info btn-sm"><i class="fa fa-undo icon-embed-btn"></i><?=gettext("Clear")?></a>
382
			</div>
383
			<div class="col-sm-10 col-sm-offset-2">
384
				<span class="help-block"><?=gettext('Enter a search string or *nix regular expression to search certificate names and distinguished names.')?></span>
385
			</div>
386
		</div>
387
	</div>
388
</div>
389

    
390
<div class="panel panel-default">
391
	<div class="panel-heading"><h2 class="panel-title"><?=gettext('Certificate Authorities')?></h2></div>
392
	<div class="panel-body">
393
		<div class="table-responsive">
394
		<table id="catable" class="table table-striped table-hover table-rowdblclickedit sortable-theme-bootstrap" data-sortable>
395
			<thead>
396
				<tr>
397
					<th><?=gettext("Name")?></th>
398
					<th><?=gettext("Internal")?></th>
399
					<th><?=gettext("Issuer")?></th>
400
					<th><?=gettext("Certificates")?></th>
401
					<th><?=gettext("Distinguished Name")?></th>
402
					<th><?=gettext("In Use")?></th>
403
					<th><?=gettext("Actions")?></th>
404
				</tr>
405
			</thead>
406
			<tbody>
407
<?php
408
$pluginparams = array();
409
$pluginparams['type'] = 'certificates';
410
$pluginparams['event'] = 'used_ca';
411
$certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
412

    
413
foreach ($a_ca as $ca):
414
	$name = htmlspecialchars($ca['descr']);
415
	$subj = cert_get_subject($ca['crt']);
416
	$issuer = cert_get_issuer($ca['crt']);
417
	if ($subj == $issuer) {
418
		$issuer_name = gettext("self-signed");
419
	} else {
420
		$issuer_name = gettext("external");
421
	}
422
	$subj = htmlspecialchars(cert_escape_x509_chars($subj, true));
423
	$issuer = htmlspecialchars($issuer);
424
	$certcount = 0;
425

    
426
	$issuer_ca = lookup_ca($ca['caref']);
427
	if ($issuer_ca) {
428
		$issuer_name = $issuer_ca['descr'];
429
	}
430

    
431
	foreach ($a_cert as $cert) {
432
		if ($cert['caref'] == $ca['refid']) {
433
			$certcount++;
434
		}
435
	}
436

    
437
	foreach ($a_ca as $cert) {
438
		if ($cert['caref'] == $ca['refid']) {
439
			$certcount++;
440
		}
441
	}
442
?>
443
				<tr>
444
					<td><?=$name?></td>
445
					<td><i class="fa fa-<?= (!empty($ca['prv'])) ? "check" : "times" ; ?>"></i></td>
446
					<td><i><?=$issuer_name?></i></td>
447
					<td><?=$certcount?></td>
448
					<td>
449
						<?=$subj?>
450
						<?php cert_print_infoblock($ca); ?>
451
						<?php cert_print_dates($ca);?>
452
					</td>
453
					<td class="text-nowrap">
454
						<?php if (is_openvpn_server_ca($ca['refid'])): ?>
455
							<?=gettext("OpenVPN Server")?><br/>
456
						<?php endif?>
457
						<?php if (is_openvpn_client_ca($ca['refid'])): ?>
458
							<?=gettext("OpenVPN Client")?><br/>
459
						<?php endif?>
460
						<?php if (is_ipsec_peer_ca($ca['refid'])): ?>
461
							<?=gettext("IPsec Tunnel")?><br/>
462
						<?php endif?>
463
						<?php if (is_ldap_peer_ca($ca['refid'])): ?>
464
							<?=gettext("LDAP Server")?>
465
						<?php endif?>
466
						<?php echo cert_usedby_description($ca['refid'], $certificates_used_by_packages); ?>
467
					</td>
468
					<td class="text-nowrap">
469
						<a class="fa fa-pencil"	title="<?=gettext("Edit CA")?>"	href="system_camanager.php?act=edit&amp;id=<?=$ca['refid']?>"></a>
470
						<a class="fa fa-certificate"	title="<?=gettext("Export CA")?>"	href="system_camanager.php?act=exp&amp;id=<?=$ca['refid']?>"></a>
471
					<?php if ($ca['prv']): ?>
472
						<a class="fa fa-key"	title="<?=gettext("Export key")?>"	href="system_camanager.php?act=expkey&amp;id=<?=$ca['refid']?>"></a>
473
					<?php endif?>
474
					<?php if (is_cert_locally_renewable($ca)): ?>
475
						<a href="system_certmanager_renew.php?type=ca&amp;refid=<?=$ca['refid']?>" class="fa fa-repeat" title="<?=gettext("Reissue/Renew")?>"></a>
476
					<?php endif ?>
477
					<?php if (!ca_in_use($ca['refid'])): ?>
478
						<a class="fa fa-trash" 	title="<?=gettext("Delete CA and its CRLs")?>"	href="system_camanager.php?act=del&amp;id=<?=$ca['refid']?>" usepost ></a>
479
					<?php endif?>
480
					</td>
481
				</tr>
482
<?php endforeach; ?>
483
			</tbody>
484
		</table>
485
		</div>
486
	</div>
487
</div>
488

    
489
<nav class="action-buttons">
490
	<a href="?act=new" class="btn btn-success btn-sm">
491
		<i class="fa fa-plus icon-embed-btn"></i>
492
		<?=gettext("Add")?>
493
	</a>
494
</nav>
495
<script type="text/javascript">
496
//<![CDATA[
497

    
498
events.push(function() {
499

    
500
	// Make these controls plain buttons
501
	$("#btnsearch").prop('type', 'button');
502
	$("#btnclear").prop('type', 'button');
503

    
504
	// Search for a term in the entry name and/or dn
505
	$("#btnsearch").click(function() {
506
		var searchstr = $('#searchstr').val().toLowerCase();
507
		var table = $("table tbody");
508
		var where = $('#where').val();
509

    
510
		table.find('tr').each(function (i) {
511
			var $tds = $(this).find('td'),
512
				shortname = $tds.eq(0).text().trim().toLowerCase(),
513
				dn = $tds.eq(4).text().trim().toLowerCase();
514

    
515
			regexp = new RegExp(searchstr);
516
			if (searchstr.length > 0) {
517
				if (!(regexp.test(shortname) && (where != 1)) && !(regexp.test(dn) && (where != 0))) {
518
					$(this).hide();
519
				} else {
520
					$(this).show();
521
				}
522
			} else {
523
				$(this).show();	// A blank search string shows all
524
			}
525
		});
526
	});
527

    
528
	// Clear the search term and unhide all rows (that were hidden during a previous search)
529
	$("#btnclear").click(function() {
530
		var table = $("table tbody");
531

    
532
		$('#searchstr').val("");
533

    
534
		table.find('tr').each(function (i) {
535
			$(this).show();
536
		});
537
	});
538

    
539
	// Hitting the enter key will do the same as clicking the search button
540
	$("#searchstr").on("keyup", function (event) {
541
		if (event.keyCode == 13) {
542
			$("#btnsearch").get(0).click();
543
		}
544
	});
545
});
546
//]]>
547
</script>
548

    
549
<?php
550
	include("foot.inc");
551
	exit;
552
}
553

    
554
$form = new Form;
555
//$form->setAction('system_camanager.php?act=edit');
556
if (isset($id) && $thisca) {
557
	$form->addGlobal(new Form_Input(
558
		'id',
559
		null,
560
		'hidden',
561
		$id
562
	));
563
}
564

    
565
if ($act == "edit") {
566
	$form->addGlobal(new Form_Input(
567
		'refid',
568
		null,
569
		'hidden',
570
		$pconfig['refid']
571
	));
572
}
573

    
574
$section = new Form_Section('Create / Edit CA');
575

    
576
$section->addInput(new Form_Input(
577
	'descr',
578
	'*Descriptive name',
579
	'text',
580
	$pconfig['descr']
581
));
582

    
583
if (!isset($id) || $act == "edit") {
584
	$section->addInput(new Form_Select(
585
		'method',
586
		'*Method',
587
		$pconfig['method'],
588
		$ca_methods
589
	))->toggles();
590
}
591

    
592
$section->addInput(new Form_Checkbox(
593
	'trust',
594
	'Trust Store',
595
	'Add this Certificate Authority to the Operating System Trust Store',
596
	$pconfig['trust']
597
))->setHelp('When enabled, the contents of the CA will be added to the trust ' .
598
	'store so that they will be trusted by the operating system.');
599

    
600
$section->addInput(new Form_Checkbox(
601
	'randomserial',
602
	'Randomize Serial',
603
	'Use random serial numbers when signing certifices',
604
	$pconfig['randomserial']
605
))->setHelp('When enabled, if this CA is capable of signing certificates then ' .
606
		'serial numbers for certificates signed by this CA will be ' .
607
		'automatically randomized and checked for uniqueness instead of ' .
608
		'using the sequential value from Next Certificate Serial.');
609

    
610
$form->add($section);
611

    
612
$section = new Form_Section('Existing Certificate Authority');
613
$section->addClass('toggle-existing collapse');
614

    
615
$section->addInput(new Form_Textarea(
616
	'cert',
617
	'*Certificate data',
618
	$pconfig['cert']
619
))->setHelp('Paste a certificate in X.509 PEM format here.');
620

    
621
$section->addInput(new Form_Textarea(
622
	'key',
623
	'Certificate Private Key (optional)',
624
	$pconfig['key']
625
))->setHelp('Paste the private key for the above certificate here. This is '.
626
	'optional in most cases, but is required when generating a '.
627
	'Certificate Revocation List (CRL).');
628

    
629
$section->addInput(new Form_Input(
630
	'serial',
631
	'Next Certificate Serial',
632
	'number',
633
	$pconfig['serial']
634
))->setHelp('Enter a decimal number to be used as a sequential serial number for ' .
635
	'the next certificate to be signed by this CA.');
636

    
637
$form->add($section);
638

    
639
$section = new Form_Section('Internal Certificate Authority');
640
$section->addClass('toggle-internal', 'toggle-intermediate', 'collapse');
641

    
642
$allCas = array();
643
foreach ($a_ca as $ca) {
644
	if (!$ca['prv']) {
645
			continue;
646
	}
647

    
648
	$allCas[ $ca['refid'] ] = $ca['descr'];
649
}
650

    
651
$group = new Form_Group('*Signing Certificate Authority');
652
$group->addClass('toggle-intermediate', 'collapse');
653
$group->add(new Form_Select(
654
	'caref',
655
	null,
656
	$pconfig['caref'],
657
	$allCas
658
));
659
$section->add($group);
660

    
661
$section->addInput(new Form_Select(
662
	'keytype',
663
	'*Key type',
664
	$pconfig['keytype'],
665
	array_combine($ca_keytypes, $ca_keytypes)
666
));
667

    
668
$group = new Form_Group($i == 0 ? '*Key length':'');
669
$group->addClass('rsakeys');
670
$group->add(new Form_Select(
671
	'keylen',
672
	null,
673
	$pconfig['keylen'],
674
	array_combine($ca_keylens, $ca_keylens)
675
))->setHelp('The length to use when generating a new RSA key, in bits. %1$s' .
676
	'The Key Length should not be lower than 2048 or some platforms ' .
677
	'may consider the certificate invalid.', '<br/>');
678
$section->add($group);
679

    
680
$group = new Form_Group($i == 0 ? '*Elliptic Curve Name':'');
681
$group->addClass('ecnames');
682
$group->add(new Form_Select(
683
	'ecname',
684
	null,
685
	$pconfig['ecname'],
686
	$openssl_ecnames
687
))->setHelp('Curves may not be compatible with all uses. Known compatible curve uses are denoted in brackets.');
688
$section->add($group);
689

    
690
$section->addInput(new Form_Select(
691
	'digest_alg',
692
	'*Digest Algorithm',
693
	$pconfig['digest_alg'],
694
	array_combine($openssl_digest_algs, $openssl_digest_algs)
695
))->setHelp('The digest method used when the CA is signed. %1$s' .
696
	'The best practice is to use an algorithm stronger than SHA1. '.
697
	'Some platforms may consider weaker digest algorithms invalid', '<br/>');
698

    
699
$section->addInput(new Form_Input(
700
	'lifetime',
701
	'*Lifetime (days)',
702
	'number',
703
	$pconfig['lifetime'],
704
	['max' => $max_lifetime]
705
));
706

    
707
$section->addInput(new Form_Input(
708
	'dn_commonname',
709
	'*Common Name',
710
	'text',
711
	$pconfig['dn_commonname'],
712
	['placeholder' => 'e.g. internal-ca']
713
));
714

    
715
$section->addInput(new Form_StaticText(
716
	null,
717
	gettext('The following certificate authority subject components are optional and may be left blank.')
718
));
719

    
720
$section->addInput(new Form_Select(
721
	'dn_country',
722
	'Country Code',
723
	$pconfig['dn_country'],
724
	get_cert_country_codes()
725
));
726

    
727
$section->addInput(new Form_Input(
728
	'dn_state',
729
	'State or Province',
730
	'text',
731
	$pconfig['dn_state'],
732
	['placeholder' => 'e.g. Texas']
733
));
734

    
735
$section->addInput(new Form_Input(
736
	'dn_city',
737
	'City',
738
	'text',
739
	$pconfig['dn_city'],
740
	['placeholder' => 'e.g. Austin']
741
));
742

    
743
$section->addInput(new Form_Input(
744
	'dn_organization',
745
	'Organization',
746
	'text',
747
	$pconfig['dn_organization'],
748
	['placeholder' => 'e.g. My Company Inc']
749
));
750

    
751
$section->addInput(new Form_Input(
752
	'dn_organizationalunit',
753
	'Organizational Unit',
754
	'text',
755
	$pconfig['dn_organizationalunit'],
756
	['placeholder' => 'e.g. My Department Name (optional)']
757
));
758

    
759
$form->add($section);
760

    
761
print $form;
762

    
763
$internal_ca_count = 0;
764
foreach ($a_ca as $ca) {
765
	if ($ca['prv']) {
766
		$internal_ca_count++;
767
	}
768
}
769

    
770
?>
771
<script type="text/javascript">
772
//<![CDATA[
773
events.push(function() {
774
	function change_keytype() {
775
	hideClass('rsakeys', ($('#keytype').val() != 'RSA'));
776
		hideClass('ecnames', ($('#keytype').val() != 'ECDSA'));
777
	}
778

    
779
	$('#keytype').change(function () {
780
		change_keytype();
781
	});
782

    
783
	function check_keylen() {
784
		var min_keylen = <?= $cert_strict_values['min_private_key_bits'] ?>;
785
		var klid = '#keylen';
786
		/* Color the Parent/Label */
787
		if (parseInt($(klid).val()) < min_keylen) {
788
			$(klid).parent().parent().removeClass("text-normal").addClass("text-warning");
789
		} else {
790
			$(klid).parent().parent().removeClass("text-warning").addClass("text-normal");
791
		}
792
		/* Color individual options */
793
		$(klid + " option").filter(function() {
794
			return parseInt($(this).val()) < min_keylen;
795
		}).removeClass("text-normal").addClass("text-warning").siblings().removeClass("text-warning").addClass("text-normal");
796
	}
797

    
798
	function check_digest() {
799
		var weak_algs = <?= json_encode($cert_strict_values['digest_blacklist']) ?>;
800
		var daid = '#digest_alg';
801
		/* Color the Parent/Label */
802
		if (jQuery.inArray($(daid).val(), weak_algs) > -1) {
803
			$(daid).parent().parent().removeClass("text-normal").addClass("text-warning");
804
		} else {
805
			$(daid).parent().parent().removeClass("text-warning").addClass("text-normal");
806
		}
807
		/* Color individual options */
808
		$(daid + " option").filter(function() {
809
			return (jQuery.inArray($(this).val(), weak_algs) > -1);
810
		}).removeClass("text-normal").addClass("text-warning").siblings().removeClass("text-warning").addClass("text-normal");
811
	}
812

    
813
	// ---------- Control change handlers ---------------------------------------------------------
814

    
815
	$('#method').on('change', function() {
816
		check_keylen();
817
		check_digest();
818
	});
819

    
820
	$('#keylen').on('change', function() {
821
		check_keylen();
822
	});
823

    
824
	$('#digest_alg').on('change', function() {
825
		check_digest();
826
	});
827

    
828
	// ---------- On initial page load ------------------------------------------------------------
829
	change_keytype();
830
	check_keylen();
831
	check_digest();
832
});
833
//]]>
834
</script>
835
<?php
836
include('foot.inc');
(192-192/227)