Project

General

Profile

Download (24.8 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-2019 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 = openssl_get_curve_names();
48

    
49
if (isset($_REQUEST['id']) && is_numericint($_REQUEST['id'])) {
50
	$id = $_REQUEST['id'];
51
}
52

    
53
init_config_arr(array('ca'));
54
$a_ca = &$config['ca'];
55

    
56
init_config_arr(array('cert'));
57
$a_cert = &$config['cert'];
58

    
59
init_config_arr(array('crl'));
60
$a_crl = &$config['crl'];
61

    
62
if ($_REQUEST['act']) {
63
	$act = $_REQUEST['act'];
64
}
65

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

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

    
135
if ($_POST['save']) {
136
	unset($input_errors);
137
	$input_errors = array();
138
	$pconfig = $_POST;
139

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

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

    
216
	if (!empty($_POST['serial']) && !cert_validate_serial($_POST['serial'])) {
217
		$input_errors[] = gettext("Please enter a valid integer serial number.");
218
	}
219

    
220
	/* save modifications */
221
	if (!$input_errors) {
222
		$ca = array();
223
		if (!isset($pconfig['refid']) || empty($pconfig['refid'])) {
224
			$ca['refid'] = uniqid();
225
		} else {
226
			$ca['refid'] = $pconfig['refid'];
227
		}
228

    
229
		if (isset($id) && $a_ca[$id]) {
230
			$ca = $a_ca[$id];
231
		}
232

    
233
		$ca['descr'] = $pconfig['descr'];
234
		$ca['trust'] = ($pconfig['trust'] == 'yes') ? "enabled" : "disabled";
235
		$ca['randomserial'] = ($pconfig['randomserial'] == 'yes') ? "enabled" : "disabled";
236

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

    
303
		if (isset($id) && $a_ca[$id]) {
304
			$a_ca[$id] = $ca;
305
		} else {
306
			$a_ca[] = $ca;
307
		}
308

    
309
		if (!$input_errors) {
310
			write_config();
311
			ca_setup_trust_store();
312
			pfSenseHeader("system_camanager.php");
313
		}
314
	}
315
}
316

    
317
$pgtitle = array(gettext("System"), gettext("Certificate Manager"), gettext("CAs"));
318
$pglinks = array("", "system_camanager.php", "system_camanager.php");
319

    
320
if ($act == "new" || $act == "edit" || $act == gettext("Save") || $input_errors) {
321
	$pgtitle[] = gettext('Edit');
322
	$pglinks[] = "@self";
323
}
324
include("head.inc");
325

    
326
if ($input_errors) {
327
	print_input_errors($input_errors);
328
}
329

    
330
if ($savemsg) {
331
	print_info_box($savemsg, 'success');
332
}
333

    
334
$tab_array = array();
335
$tab_array[] = array(gettext("CAs"), true, "system_camanager.php");
336
$tab_array[] = array(gettext("Certificates"), false, "system_certmanager.php");
337
$tab_array[] = array(gettext("Certificate Revocation"), false, "system_crlmanager.php");
338
display_top_tabs($tab_array);
339

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

    
377
<div class="panel panel-default">
378
	<div class="panel-heading"><h2 class="panel-title"><?=gettext('Certificate Authorities')?></h2></div>
379
	<div class="panel-body">
380
		<div class="table-responsive">
381
		<table id="catable" class="table table-striped table-hover table-rowdblclickedit sortable-theme-bootstrap" data-sortable>
382
			<thead>
383
				<tr>
384
					<th><?=gettext("Name")?></th>
385
					<th><?=gettext("Internal")?></th>
386
					<th><?=gettext("Issuer")?></th>
387
					<th><?=gettext("Certificates")?></th>
388
					<th><?=gettext("Distinguished Name")?></th>
389
					<th><?=gettext("In Use")?></th>
390
					<th><?=gettext("Actions")?></th>
391
				</tr>
392
			</thead>
393
			<tbody>
394
<?php
395
$pluginparams = array();
396
$pluginparams['type'] = 'certificates';
397
$pluginparams['event'] = 'used_ca';
398
$certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
399

    
400
foreach ($a_ca as $i => $ca):
401
	$name = htmlspecialchars($ca['descr']);
402
	$subj = cert_get_subject($ca['crt']);
403
	$issuer = cert_get_issuer($ca['crt']);
404
	if ($subj == $issuer) {
405
		$issuer_name = gettext("self-signed");
406
	} else {
407
		$issuer_name = gettext("external");
408
	}
409
	$subj = htmlspecialchars(cert_escape_x509_chars($subj, true));
410
	$issuer = htmlspecialchars($issuer);
411
	$certcount = 0;
412

    
413
	$issuer_ca = lookup_ca($ca['caref']);
414
	if ($issuer_ca) {
415
		$issuer_name = $issuer_ca['descr'];
416
	}
417

    
418
	foreach ($a_cert as $cert) {
419
		if ($cert['caref'] == $ca['refid']) {
420
			$certcount++;
421
		}
422
	}
423

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

    
476
<nav class="action-buttons">
477
	<a href="?act=new" class="btn btn-success btn-sm">
478
		<i class="fa fa-plus icon-embed-btn"></i>
479
		<?=gettext("Add")?>
480
	</a>
481
</nav>
482
<script type="text/javascript">
483
//<![CDATA[
484

    
485
events.push(function() {
486

    
487
	// Make these controls plain buttons
488
	$("#btnsearch").prop('type', 'button');
489
	$("#btnclear").prop('type', 'button');
490

    
491
	// Search for a term in the entry name and/or dn
492
	$("#btnsearch").click(function() {
493
		var searchstr = $('#searchstr').val().toLowerCase();
494
		var table = $("table tbody");
495
		var where = $('#where').val();
496

    
497
		table.find('tr').each(function (i) {
498
			var $tds = $(this).find('td'),
499
				shortname = $tds.eq(0).text().trim().toLowerCase(),
500
				dn = $tds.eq(4).text().trim().toLowerCase();
501

    
502
			regexp = new RegExp(searchstr);
503
			if (searchstr.length > 0) {
504
				if (!(regexp.test(shortname) && (where != 1)) && !(regexp.test(dn) && (where != 0))) {
505
					$(this).hide();
506
				} else {
507
					$(this).show();
508
				}
509
			} else {
510
				$(this).show();	// A blank search string shows all
511
			}
512
		});
513
	});
514

    
515
	// Clear the search term and unhide all rows (that were hidden during a previous search)
516
	$("#btnclear").click(function() {
517
		var table = $("table tbody");
518

    
519
		$('#searchstr').val("");
520

    
521
		table.find('tr').each(function (i) {
522
			$(this).show();
523
		});
524
	});
525

    
526
	// Hitting the enter key will do the same as clicking the search button
527
	$("#searchstr").on("keyup", function (event) {
528
		if (event.keyCode == 13) {
529
			$("#btnsearch").get(0).click();
530
		}
531
	});
532
});
533
//]]>
534
</script>
535

    
536
<?php
537
	include("foot.inc");
538
	exit;
539
}
540

    
541
$form = new Form;
542
//$form->setAction('system_camanager.php?act=edit');
543
if (isset($id) && $a_ca[$id]) {
544
	$form->addGlobal(new Form_Input(
545
		'id',
546
		null,
547
		'hidden',
548
		$id
549
	));
550
}
551

    
552
if ($act == "edit") {
553
	$form->addGlobal(new Form_Input(
554
		'refid',
555
		null,
556
		'hidden',
557
		$pconfig['refid']
558
	));
559
}
560

    
561
$section = new Form_Section('Create / Edit CA');
562

    
563
$section->addInput(new Form_Input(
564
	'descr',
565
	'*Descriptive name',
566
	'text',
567
	$pconfig['descr']
568
));
569

    
570
$section->addInput(new Form_Checkbox(
571
	'trust',
572
	'Trust Store',
573
	'Add this Certificate Authority to the Operating System Trust Store',
574
	$pconfig['trust']
575
))->setHelp('When enabled, the contents of the CA will be added to the trust ' .
576
	'store so that they will be trusted by the operating system.');
577

    
578
if (!isset($id) || $act == "edit") {
579
	$section->addInput(new Form_Select(
580
		'method',
581
		'*Method',
582
		$pconfig['method'],
583
		$ca_methods
584
	))->toggles();
585
}
586

    
587
$form->add($section);
588

    
589
$section = new Form_Section('Existing Certificate Authority');
590
$section->addClass('toggle-existing collapse');
591

    
592
$section->addInput(new Form_Textarea(
593
	'cert',
594
	'*Certificate data',
595
	$pconfig['cert']
596
))->setHelp('Paste a certificate in X.509 PEM format here.');
597

    
598
$section->addInput(new Form_Textarea(
599
	'key',
600
	'Certificate Private Key (optional)',
601
	$pconfig['key']
602
))->setHelp('Paste the private key for the above certificate here. This is '.
603
	'optional in most cases, but is required when generating a '.
604
	'Certificate Revocation List (CRL).');
605

    
606
$section->addInput(new Form_Checkbox(
607
	'randomserial',
608
	'Randomize Serial',
609
	'Use random serial numbers when signing certifices',
610
	$pconfig['randomserial']
611
))->setHelp('When enabled, serial numbers for certificates signed by this CA ' .
612
		'will be automatically randomized and checked for uniqueness ' .
613
		'instead of using the sequential value from Next Certificate Serial.');
614

    
615
$section->addInput(new Form_Input(
616
	'serial',
617
	'Next Certificate Serial',
618
	'number',
619
	$pconfig['serial']
620
))->setHelp('Enter a decimal number to be used as a sequential serial number for ' .
621
	'the next certificate to be signed by this CA.');
622

    
623
$form->add($section);
624

    
625
$section = new Form_Section('Internal Certificate Authority');
626
$section->addClass('toggle-internal', 'toggle-intermediate', 'collapse');
627

    
628
$allCas = array();
629
foreach ($a_ca as $ca) {
630
	if (!$ca['prv']) {
631
			continue;
632
	}
633

    
634
	$allCas[ $ca['refid'] ] = $ca['descr'];
635
}
636

    
637
$group = new Form_Group('*Signing Certificate Authority');
638
$group->addClass('toggle-intermediate', 'collapse');
639
$group->add(new Form_Select(
640
	'caref',
641
	null,
642
	$pconfig['caref'],
643
	$allCas
644
));
645
$section->add($group);
646

    
647
$section->addInput(new Form_Select(
648
	'keytype',
649
	'*Key type',
650
	$pconfig['keytype'],
651
	array_combine($ca_keytypes, $ca_keytypes)
652
));
653

    
654
$group = new Form_Group($i == 0 ? '*Key length':'');
655
$group->addClass('rsakeys');
656
$group->add(new Form_Select(
657
	'keylen',
658
	null,
659
	$pconfig['keylen'],
660
	array_combine($ca_keylens, $ca_keylens)
661
))->setHelp('The length to use when generating a new RSA key, in bits. %1$s' .
662
	'The Key Length should not be lower than 2048 or some platforms ' .
663
	'may consider the certificate invalid.', '<br/>');
664
$section->add($group);
665

    
666
$group = new Form_Group($i == 0 ? '*Elliptic Curve Name':'');
667
$group->addClass('ecnames');
668
$group->add(new Form_Select(
669
	'ecname',
670
	null,
671
	$pconfig['ecname'],
672
	array_combine($openssl_ecnames, $openssl_ecnames)
673
));
674
$section->add($group);
675

    
676
$section->addInput(new Form_Select(
677
	'digest_alg',
678
	'*Digest Algorithm',
679
	$pconfig['digest_alg'],
680
	array_combine($openssl_digest_algs, $openssl_digest_algs)
681
))->setHelp('The digest method used when the CA is signed. %1$s' .
682
	'The best practice is to use an algorithm stronger than SHA1. '.
683
	'Some platforms may consider weaker digest algorithms invalid', '<br/>');
684

    
685
$section->addInput(new Form_Input(
686
	'lifetime',
687
	'*Lifetime (days)',
688
	'number',
689
	$pconfig['lifetime'],
690
	['max' => $max_lifetime]
691
));
692

    
693
$section->addInput(new Form_Input(
694
	'dn_commonname',
695
	'*Common Name',
696
	'text',
697
	$pconfig['dn_commonname'],
698
	['placeholder' => 'e.g. internal-ca']
699
));
700

    
701
$section->addInput(new Form_StaticText(
702
	null,
703
	gettext('The following certificate authority subject components are optional and may be left blank.')
704
));
705

    
706
$section->addInput(new Form_Select(
707
	'dn_country',
708
	'Country Code',
709
	$pconfig['dn_country'],
710
	get_cert_country_codes()
711
));
712

    
713
$section->addInput(new Form_Input(
714
	'dn_state',
715
	'State or Province',
716
	'text',
717
	$pconfig['dn_state'],
718
	['placeholder' => 'e.g. Texas']
719
));
720

    
721
$section->addInput(new Form_Input(
722
	'dn_city',
723
	'City',
724
	'text',
725
	$pconfig['dn_city'],
726
	['placeholder' => 'e.g. Austin']
727
));
728

    
729
$section->addInput(new Form_Input(
730
	'dn_organization',
731
	'Organization',
732
	'text',
733
	$pconfig['dn_organization'],
734
	['placeholder' => 'e.g. My Company Inc']
735
));
736

    
737
$section->addInput(new Form_Input(
738
	'dn_organizationalunit',
739
	'Organizational Unit',
740
	'text',
741
	$pconfig['dn_organizationalunit'],
742
	['placeholder' => 'e.g. My Department Name (optional)']
743
));
744

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

    
747
print $form;
748

    
749
$internal_ca_count = 0;
750
foreach ($a_ca as $ca) {
751
	if ($ca['prv']) {
752
		$internal_ca_count++;
753
	}
754
}
755

    
756
?>
757
<script type="text/javascript">
758
//<![CDATA[
759
events.push(function() {
760
	function change_keytype() {
761
	hideClass('rsakeys', ($('#keytype').val() != 'RSA'));
762
		hideClass('ecnames', ($('#keytype').val() != 'ECDSA'));
763
	}
764

    
765
	$('#keytype').change(function () {
766
		change_keytype();
767
	});
768

    
769
	function check_keylen() {
770
		var min_keylen = <?= $cert_strict_values['min_private_key_bits'] ?>;
771
		var klid = '#keylen';
772
		/* Color the Parent/Label */
773
		if (parseInt($(klid).val()) < min_keylen) {
774
			$(klid).parent().parent().removeClass("text-normal").addClass("text-warning");
775
		} else {
776
			$(klid).parent().parent().removeClass("text-warning").addClass("text-normal");
777
		}
778
		/* Color individual options */
779
		$(klid + " option").filter(function() {
780
			return parseInt($(this).val()) < min_keylen;
781
		}).removeClass("text-normal").addClass("text-warning").siblings().removeClass("text-warning").addClass("text-normal");
782
	}
783

    
784
	function check_digest() {
785
		var weak_algs = <?= json_encode($cert_strict_values['digest_blacklist']) ?>;
786
		var daid = '#digest_alg';
787
		/* Color the Parent/Label */
788
		if (jQuery.inArray($(daid).val(), weak_algs) > -1) {
789
			$(daid).parent().parent().removeClass("text-normal").addClass("text-warning");
790
		} else {
791
			$(daid).parent().parent().removeClass("text-warning").addClass("text-normal");
792
		}
793
		/* Color individual options */
794
		$(daid + " option").filter(function() {
795
			return (jQuery.inArray($(this).val(), weak_algs) > -1);
796
		}).removeClass("text-normal").addClass("text-warning").siblings().removeClass("text-warning").addClass("text-normal");
797
	}
798

    
799
	// ---------- Control change handlers ---------------------------------------------------------
800

    
801
	$('#method').on('change', function() {
802
		check_keylen();
803
		check_digest();
804
	});
805

    
806
	$('#keylen').on('change', function() {
807
		check_keylen();
808
	});
809

    
810
	$('#digest_alg').on('change', function() {
811
		check_digest();
812
	});
813

    
814
	// ---------- On initial page load ------------------------------------------------------------
815
	change_keytype();
816
	check_keylen();
817
	check_digest();
818
});
819
//]]>
820
</script>
821
<?php
822
include('foot.inc');
(192-192/227)