Project

General

Profile

« Previous | Next » 

Revision 7e83055a

Added by Jim Pingle over 5 years ago

CA/Cert/CRL code optimizations

While here, use the new download function when exporting items

View differences:

src/usr/local/www/system_camanager.php
63 63
	$act = $_REQUEST['act'];
64 64
}
65 65

  
66
if ($_POST['act'] == "del") {
67

  
68
	if (!isset($a_ca[$id])) {
69
		pfSenseHeader("system_camanager.php");
70
		exit;
71
	}
72

  
73
	/* Only remove CA reference when deleting. It can be reconnected if a new matching CA is imported */
74
	$index = count($a_cert) - 1;
75
	for (;$index >= 0; $index--) {
76
		if ($a_cert[$index]['caref'] == $a_ca[$id]['refid']) {
77
			unset($a_cert[$index]['caref']);
78
		}
79
	}
80

  
81
	/* Remove any CRLs for this CA, there is no way to recover the connection once the CA has been removed. */
82
	$index = count($a_crl) - 1;
83
	for (;$index >= 0; $index--) {
84
		if ($a_crl[$index]['caref'] == $a_ca[$id]['refid']) {
85
			unset($a_crl[$index]);
86
		}
87
	}
88

  
89
	$name = $a_ca[$id]['descr'];
90
	unset($a_ca[$id]);
91
	write_config();
92
	ca_setup_trust_store();
93
	$savemsg = sprintf(gettext("Certificate Authority %s and its CRLs (if any) successfully deleted."), htmlspecialchars($name));
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))) {
94 72
	pfSenseHeader("system_camanager.php");
95 73
	exit;
96 74
}
97 75

  
98
if ($act == "edit") {
99
	if (!$a_ca[$id]) {
100
		pfSenseHeader("system_camanager.php");
101
		exit;
102
	}
103
	$pconfig['method'] = 'existing';
104
	$pconfig['descr']  = $a_ca[$id]['descr'];
105
	$pconfig['refid']  = $a_ca[$id]['refid'];
106
	$pconfig['cert']   = base64_decode($a_ca[$id]['crt']);
107
	$pconfig['serial'] = $a_ca[$id]['serial'];
108
	$pconfig['trust']  = ($a_ca[$id]['trust'] == 'enabled');
109
	$pconfig['randomserial']  = ($a_ca[$id]['randomserial'] == 'enabled');
110
	if (!empty($a_ca[$id]['prv'])) {
111
		$pconfig['key'] = base64_decode($a_ca[$id]['prv']);
112
	}
113
}
114

  
115
if ($act == "new") {
116
	$pconfig['method'] = $_POST['method'];
117
	$pconfig['keytype'] = "RSA";
118
	$pconfig['keylen'] = "2048";
119
	$pconfig['ecname'] = "brainpoolP256r1";
120
	$pconfig['digest_alg'] = "sha256";
121
	$pconfig['lifetime'] = $default_lifetime;
122
	$pconfig['dn_commonname'] = "internal-ca";
123
}
124

  
125
if ($act == "exp") {
126

  
127
	if (!$a_ca[$id]) {
128
		pfSenseHeader("system_camanager.php");
129
		exit;
130
	}
131

  
132
	$exp_name = urlencode("{$a_ca[$id]['descr']}.crt");
133
	$exp_data = base64_decode($a_ca[$id]['crt']);
134
	$exp_size = strlen($exp_data);
135

  
136
	header("Content-Type: application/octet-stream");
137
	header("Content-Disposition: attachment; filename={$exp_name}");
138
	header("Content-Length: $exp_size");
139
	echo $exp_data;
140
	exit;
141
}
142

  
143
if ($act == "expkey") {
144

  
145
	if (!$a_ca[$id]) {
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));
146 97
		pfSenseHeader("system_camanager.php");
147 98
		exit;
148
	}
149

  
150
	$exp_name = urlencode("{$a_ca[$id]['descr']}.key");
151
	$exp_data = base64_decode($a_ca[$id]['prv']);
152
	$exp_size = strlen($exp_data);
153

  
154
	header("Content-Type: application/octet-stream");
155
	header("Content-Disposition: attachment; filename={$exp_name}");
156
	header("Content-Length: $exp_size");
157
	echo $exp_data;
158
	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;
159 133
}
160 134

  
161 135
if ($_POST['save']) {
162

  
163 136
	unset($input_errors);
164 137
	$input_errors = array();
165 138
	$pconfig = $_POST;
166 139

  
167 140
	/* input validation */
168
	if ($pconfig['method'] == "existing") {
169
		$reqdfields = explode(" ", "descr cert");
170
		$reqdfieldsn = array(
171
			gettext("Descriptive name"),
172
			gettext("Certificate data"));
173
		if ($_POST['cert'] && (!strstr($_POST['cert'], "BEGIN CERTIFICATE") || !strstr($_POST['cert'], "END CERTIFICATE"))) {
174
			$input_errors[] = gettext("This certificate does not appear to be valid.");
175
		}
176
		if ($_POST['key'] && strstr($_POST['key'], "ENCRYPTED")) {
177
			$input_errors[] = gettext("Encrypted private keys are not yet supported.");
178
		}
179
		if (!$input_errors && !empty($_POST['key']) && cert_get_publickey($_POST['cert'], false) != cert_get_publickey($_POST['key'], false, 'prv')) {
180
			$input_errors[] = gettext("The submitted private key does not match the submitted certificate data.");
181
		}
182
		/* we must ensure the certificate is capable of acting as a CA
183
		 * https://redmine.pfsense.org/issues/7885
184
		 */
185
		if (!$input_errors) {
186
			$purpose = cert_get_purpose($_POST['cert'], false);
187
			if ($purpose['ca'] != 'Yes') {
188
				$input_errors[] = gettext("The submitted certificate does not appear to be a Certificate Authority, import it on the Certificates tab instead.");
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.");
189 149
			}
190
		}
191
	}
192
	if ($pconfig['method'] == "internal") {
193
		$reqdfields = explode(" ",
194
			"descr keylen ecname keytype lifetime dn_commonname");
195
		$reqdfieldsn = array(
196
			gettext("Descriptive name"),
197
			gettext("Key length"),
198
			gettext("Elliptic Curve Name"),
199
			gettext("Key type"),
200
			gettext("Lifetime"),
201
			gettext("Common Name"));
202
	}
203
	if ($pconfig['method'] == "intermediate") {
204
		$reqdfields = explode(" ",
205
			"descr caref keylen ecname keytype lifetime dn_commonname");
206
		$reqdfieldsn = array(
207
			gettext("Descriptive name"),
208
			gettext("Signing Certificate Authority"),
209
			gettext("Key length"),
210
			gettext("Elliptic Curve Name"),
211
			gettext("Key type"),
212
			gettext("Lifetime"),
213
			gettext("Common Name"));
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;
214 191
	}
215 192

  
216 193
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
src/usr/local/www/system_certmanager.php
82 82

  
83 83
$act = $_REQUEST['act'];
84 84

  
85
if ($_POST['act'] == "del") {
86

  
87
	if (!isset($a_cert[$id])) {
88
		pfSenseHeader("system_certmanager.php");
89
		exit;
90
	}
91

  
92
	unset($a_cert[$id]);
93
	write_config();
94
	$savemsg = sprintf(gettext("Certificate %s successfully deleted."), htmlspecialchars($a_cert[$id]['descr']));
85
/* Actions other than 'new' require an ID.
86
 * 'del' action must be submitted via POST. */
87
if ((!empty($act) &&
88
    ($act != 'new') &&
89
    !$a_cert[$id]) ||
90
    (($act == 'del') && empty($_POST))) {
95 91
	pfSenseHeader("system_certmanager.php");
96 92
	exit;
97 93
}
98 94

  
99
if ($act == "new") {
100
	$pconfig['method'] = $_POST['method'];
101
	$pconfig['keytype'] = "RSA";
102
	$pconfig['keylen'] = "2048";
103
	$pconfig['ecname'] = "brainpoolP256r1";
104
	$pconfig['digest_alg'] = "sha256";
105
	$pconfig['csr_keytype'] = "RSA";
106
	$pconfig['csr_keylen'] = "2048";
107
	$pconfig['csr_ecname'] = "brainpoolP256r1";
108
	$pconfig['csr_digest_alg'] = "sha256";
109
	$pconfig['csrsign_digest_alg'] = "sha256";
110
	$pconfig['type'] = "user";
111
	$pconfig['lifetime'] = $default_lifetime;
112
}
113

  
114
if ($act == "exp") {
115

  
116
	if (!$a_cert[$id]) {
117
		pfSenseHeader("system_certmanager.php");
118
		exit;
119
	}
120

  
121
	$exp_name = urlencode("{$a_cert[$id]['descr']}.crt");
122
	$exp_data = base64_decode($a_cert[$id]['crt']);
123
	$exp_size = strlen($exp_data);
124

  
125
	header("Content-Type: application/octet-stream");
126
	header("Content-Disposition: attachment; filename={$exp_name}");
127
	header("Content-Length: $exp_size");
128
	echo $exp_data;
129
	exit;
130
}
131

  
132
if ($act == "req") {
133

  
134
	if (!$a_cert[$id]) {
135
		pfSenseHeader("system_certmanager.php");
136
		exit;
137
	}
138

  
139
	$exp_name = urlencode("{$a_cert[$id]['descr']}.req");
140
	$exp_data = base64_decode($a_cert[$id]['csr']);
141
	$exp_size = strlen($exp_data);
142

  
143
	header("Content-Type: application/octet-stream");
144
	header("Content-Disposition: attachment; filename={$exp_name}");
145
	header("Content-Length: $exp_size");
146
	echo $exp_data;
147
	exit;
148
}
149

  
150
if ($act == "key") {
151

  
152
	if (!$a_cert[$id]) {
153
		pfSenseHeader("system_certmanager.php");
154
		exit;
155
	}
156

  
157
	$exp_name = urlencode("{$a_cert[$id]['descr']}.key");
158
	$exp_data = base64_decode($a_cert[$id]['prv']);
159
	$exp_size = strlen($exp_data);
160

  
161
	header("Content-Type: application/octet-stream");
162
	header("Content-Disposition: attachment; filename={$exp_name}");
163
	header("Content-Length: $exp_size");
164
	echo $exp_data;
165
	exit;
166
}
167

  
168
if ($act == "p12") {
169
	if (!$a_cert[$id]) {
170
		pfSenseHeader("system_certmanager.php");
171
		exit;
172
	}
173

  
174
	$exp_name = urlencode("{$a_cert[$id]['descr']}.p12");
175
	$args = array();
176
	$args['friendly_name'] = $a_cert[$id]['descr'];
177

  
178
	$ca = lookup_ca($a_cert[$id]['caref']);
179

  
180
	if ($ca) {
181
		$args['extracerts'] = openssl_x509_read(base64_decode($ca['crt']));
182
	}
183

  
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
	openssl_pkcs12_export($res_crt, $exp_data, $res_key, null, $args);
189
	$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
if ($act == "csr") {
199
	if (!$a_cert[$id]) {
95
switch ($act) {
96
	case 'del':
97
		unset($a_cert[$id]);
98
		write_config();
99
		$savemsg = sprintf(gettext("Certificate %s successfully deleted."), htmlspecialchars($a_cert[$id]['descr']));
200 100
		pfSenseHeader("system_certmanager.php");
201 101
		exit;
202
	}
203

  
204
	$pconfig['descr'] = $a_cert[$id]['descr'];
205
	$pconfig['csr'] = base64_decode($a_cert[$id]['csr']);
102
	case 'new':
103
		/* New certificate, so set default values */
104
		$pconfig['method'] = $_POST['method'];
105
		$pconfig['keytype'] = "RSA";
106
		$pconfig['keylen'] = "2048";
107
		$pconfig['ecname'] = "brainpoolP256r1";
108
		$pconfig['digest_alg'] = "sha256";
109
		$pconfig['csr_keytype'] = "RSA";
110
		$pconfig['csr_keylen'] = "2048";
111
		$pconfig['csr_ecname'] = "brainpoolP256r1";
112
		$pconfig['csr_digest_alg'] = "sha256";
113
		$pconfig['csrsign_digest_alg'] = "sha256";
114
		$pconfig['type'] = "user";
115
		$pconfig['lifetime'] = $default_lifetime;
116
		break;
117
	case 'csr':
118
		/* Editing a CSR, so populate values */
119
		$pconfig['descr'] = $a_cert[$id]['descr'];
120
		$pconfig['csr'] = base64_decode($a_cert[$id]['csr']);
121
		break;
122
	case 'exp':
123
		/* Exporting a certificate */
124
		send_user_download('data', base64_decode($a_cert[$id]['crt']), "{$a_cert[$id]['descr']}.crt");
125
		break;
126
	case 'req':
127
		/* Exporting a certificate signing request */
128
		send_user_download('data', base64_decode($a_cert[$id]['csr']), "{$a_cert[$id]['descr']}.req");
129
		break;
130
	case 'key':
131
		/* Exporting a private key */
132
		send_user_download('data', base64_decode($a_cert[$id]['prv']), "{$a_cert[$id]['descr']}.key");
133
		break;
134
	case 'p12':
135
		/* Exporting a PKCS#12 file containing the certificate, key, and (if present) CA */
136
		$args = array();
137
		$args['friendly_name'] = $a_cert[$id]['descr'];
138
		$ca = lookup_ca($a_cert[$id]['caref']);
139
		if ($ca) {
140
			/* If the CA can be found, then add the CA to the container */
141
			$args['extracerts'] = openssl_x509_read(base64_decode($ca['crt']));
142
		}
143
		$res_crt = openssl_x509_read(base64_decode($a_cert[$id]['crt']));
144
		$res_key = openssl_pkey_get_private(base64_decode($a_cert[$id]['prv']));
145
		$exp_data = "";
146
		openssl_pkcs12_export($res_crt, $exp_data, $res_key, null, $args);
147
		send_user_download('data', $exp_data, "{$a_cert[$id]['descr']}.p12");
148
		break;
149
	default:
150
		break;
206 151
}
207 152

  
208
if ($_POST['save']) {
209

  
210
	if ($_POST['save'] == gettext("Save")) {
211
		$input_errors = array();
212
		$pconfig = $_POST;
153
if ($_POST['save'] == gettext("Save")) {
154
	/* Creating a new entry */
155
	$input_errors = array();
156
	$pconfig = $_POST;
213 157

  
214
		/* input validation */
215
		if ($pconfig['method'] == "sign") {
158
	switch ($pconfig['method']) {
159
		case 'sign':
216 160
			$reqdfields = explode(" ",
217 161
				"descr catosignwith");
218 162
			$reqdfieldsn = array(
......
235 179
			if ($_POST['lifetime'] > $max_lifetime) {
236 180
				$input_errors[] = gettext("Lifetime is longer than the maximum allowed value. Use a shorter lifetime.");
237 181
			}
238
		}
239

  
240
		if ($pconfig['method'] == "import") {
182
			break;
183
		case 'import':
241 184
			$reqdfields = explode(" ",
242 185
				"descr cert key");
243 186
			$reqdfieldsn = array(
......
251 194
			if (cert_get_publickey($_POST['cert'], false) != cert_get_publickey($_POST['key'], false, 'prv')) {
252 195
				$input_errors[] = gettext("The submitted private key does not match the submitted certificate data.");
253 196
			}
254
		}
255

  
256
		if ($pconfig['method'] == "internal") {
197
			break;
198
		case 'internal':
257 199
			$reqdfields = explode(" ",
258 200
				"descr caref keylen ecname keytype type lifetime dn_commonname");
259 201
			$reqdfieldsn = array(
......
268 210
			if ($_POST['lifetime'] > $max_lifetime) {
269 211
				$input_errors[] = gettext("Lifetime is longer than the maximum allowed value. Use a shorter lifetime.");
270 212
			}
271
		}
272

  
273
		if ($pconfig['method'] == "external") {
213
			break;
214
		case 'external':
274 215
			$reqdfields = explode(" ",
275 216
				"descr csr_keylen csr_ecname csr_keytype csr_dn_commonname");
276 217
			$reqdfieldsn = array(
......
279 220
				gettext("Elliptic Curve Name"),
280 221
				gettext("Key type"),
281 222
				gettext("Common Name"));
282
		}
283

  
284
		if ($pconfig['method'] == "existing") {
223
			break;
224
		case 'existing':
285 225
			$reqdfields = array("certref");
286 226
			$reqdfieldsn = array(gettext("Existing Certificate Choice"));
287
		}
288

  
289
		$altnames = array();
290
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
291

  
292
		if ($pconfig['method'] != "import" && $pconfig['method'] != "existing") {
293
			/* subjectAltNames */
294
			$san_typevar = 'altname_type';
295
			$san_valuevar = 'altname_value';
296
			// This is just the blank alternate name that is added for display purposes. We don't want to validate/save it
297
			if ($_POST["{$san_valuevar}0"] == "") {
298
				unset($_POST["{$san_typevar}0"]);
299
				unset($_POST["{$san_valuevar}0"]);
300
			}
301
			foreach ($_POST as $key => $value) {
302
				$entry = '';
303
				if (!substr_compare($san_typevar, $key, 0, strlen($san_typevar))) {
304
					$entry = substr($key, strlen($san_typevar));
305
					$field = 'type';
306
				} elseif (!substr_compare($san_valuevar, $key, 0, strlen($san_valuevar))) {
307
					$entry = substr($key, strlen($san_valuevar));
308
					$field = 'value';
309
				}
227
			break;
228
		default:
229
			break;
230
	}
310 231

  
311
				if (ctype_digit($entry)) {
312
					$entry++;	// Pre-bootstrap code is one-indexed, but the bootstrap code is 0-indexed
313
					$altnames[$entry][$field] = $value;
314
				}
232
	$altnames = array();
233
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
234

  
235
	if ($pconfig['method'] != "import" && $pconfig['method'] != "existing") {
236
		/* subjectAltNames */
237
		$san_typevar = 'altname_type';
238
		$san_valuevar = 'altname_value';
239
		// This is just the blank alternate name that is added for display purposes. We don't want to validate/save it
240
		if ($_POST["{$san_valuevar}0"] == "") {
241
			unset($_POST["{$san_typevar}0"]);
242
			unset($_POST["{$san_valuevar}0"]);
243
		}
244
		foreach ($_POST as $key => $value) {
245
			$entry = '';
246
			if (!substr_compare($san_typevar, $key, 0, strlen($san_typevar))) {
247
				$entry = substr($key, strlen($san_typevar));
248
				$field = 'type';
249
			} elseif (!substr_compare($san_valuevar, $key, 0, strlen($san_valuevar))) {
250
				$entry = substr($key, strlen($san_valuevar));
251
				$field = 'value';
315 252
			}
316 253

  
317
			$pconfig['altnames']['item'] = $altnames;
318

  
319
			/* Input validation for subjectAltNames */
320
			foreach ($altnames as $idx => $altname) {
321
				switch ($altname['type']) {
322
					case "DNS":
323
						if (!is_hostname($altname['value'], true) || is_ipaddr($altname['value'])) {
324
							array_push($input_errors, "DNS subjectAltName values must be valid hostnames, FQDNs or wildcard domains.");
325
						}
326
						break;
327
					case "IP":
328
						if (!is_ipaddr($altname['value'])) {
329
							array_push($input_errors, "IP subjectAltName values must be valid IP Addresses");
330
						}
331
						break;
332
					case "email":
333
						if (empty($altname['value'])) {
334
							array_push($input_errors, "An e-mail address must be provided for this type of subjectAltName");
335
						}
336
						if (preg_match("/[\!\#\$\%\^\(\)\~\?\>\<\&\/\\\,\"\']/", $altname['value'])) {
337
							array_push($input_errors, "The e-mail provided in a subjectAltName contains invalid characters.");
338
						}
339
						break;
340
					case "URI":
341
						/* Close enough? */
342
						if (!is_URL($altname['value'])) {
343
							$input_errors[] = "URI subjectAltName types must be a valid URI";
344
						}
345
						break;
346
					default:
347
						$input_errors[] = "Unrecognized subjectAltName type.";
348
				}
254
			if (ctype_digit($entry)) {
255
				$entry++;	// Pre-bootstrap code is one-indexed, but the bootstrap code is 0-indexed
256
				$altnames[$entry][$field] = $value;
349 257
			}
258
		}
350 259

  
351
			/* Make sure we do not have invalid characters in the fields for the certificate */
352

  
353
			if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
354
				array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
355
			}
260
		$pconfig['altnames']['item'] = $altnames;
356 261

  
357
			switch ($pconfig['method']) {
358
				case "internal":
359
					if (isset($_POST["keytype"]) && !in_array($_POST["keytype"], $cert_keytypes)) {
360
						array_push($input_errors, gettext("Please select a valid Key Type."));
361
					}
362
					if (isset($_POST["keylen"]) && !in_array($_POST["keylen"], $cert_keylens)) {
363
						array_push($input_errors, gettext("Please select a valid Key Length."));
364
					}
365
					if (isset($_POST["ecname"]) && !in_array($_POST["ecname"], $openssl_ecnames)) {
366
						array_push($input_errors, gettext("Please select a valid Elliptic Curve Name."));
367
					}
368
					if (!in_array($_POST["digest_alg"], $openssl_digest_algs)) {
369
						array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
262
		/* Input validation for subjectAltNames */
263
		foreach ($altnames as $idx => $altname) {
264
			switch ($altname['type']) {
265
				case "DNS":
266
					if (!is_hostname($altname['value'], true) || is_ipaddr($altname['value'])) {
267
						$input_errors[] = gettext("DNS subjectAltName values must be valid hostnames, FQDNs or wildcard domains.");
370 268
					}
371 269
					break;
372
				case "external":
373
					if (isset($_POST["csr_keytype"]) && !in_array($_POST["csr_keytype"], $cert_keytypes)) {
374
						array_push($input_errors, gettext("Please select a valid Key Type."));
270
				case "IP":
271
					if (!is_ipaddr($altname['value'])) {
272
						$input_errors[] = gettext("IP subjectAltName values must be valid IP Addresses");
375 273
					}
376
					if (isset($_POST["csr_keylen"]) && !in_array($_POST["csr_keylen"], $cert_keylens)) {
377
						array_push($input_errors, gettext("Please select a valid Key Length."));
378
					}
379
					if (isset($_POST["csr_ecname"]) && !in_array($_POST["csr_ecname"], $openssl_ecnames)) {
380
						array_push($input_errors, gettext("Please select a valid Elliptic Curve Name."));
274
					break;
275
				case "email":
276
					if (empty($altname['value'])) {
277
						$input_errors[] = gettext("An e-mail address must be provided for this type of subjectAltName");
381 278
					}
382
					if (!in_array($_POST["csr_digest_alg"], $openssl_digest_algs)) {
383
						array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
279
					if (preg_match("/[\!\#\$\%\^\(\)\~\?\>\<\&\/\\\,\"\']/", $altname['value'])) {
280
						$input_errors[] = gettext("The e-mail provided in a subjectAltName contains invalid characters.");
384 281
					}
385 282
					break;
386
				case "sign":
387
					if (!in_array($_POST["csrsign_digest_alg"], $openssl_digest_algs)) {
388
						array_push($input_errors, gettext("Please select a valid Digest Algorithm."));
283
				case "URI":
284
					/* Close enough? */
285
					if (!is_URL($altname['value'])) {
286
						$input_errors[] = gettext("URI subjectAltName types must be a valid URI");
389 287
					}
390 288
					break;
391 289
				default:
392
					break;
290
					$input_errors[] = gettext("Unrecognized subjectAltName type.");
393 291
			}
394 292
		}
395 293

  
396
		/* save modifications */
397
		if (!$input_errors) {
294
		/* Make sure we do not have invalid characters in the fields for the certificate */
295
		if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
296
			$input_errors[] = gettext("The field 'Descriptive Name' contains invalid characters.");
297
		}
398 298

  
399
			if ($pconfig['method'] == "existing") {
400
				$cert = lookup_cert($pconfig['certref']);
401
				if ($cert && $a_user) {
402
					$a_user[$userid]['cert'][] = $cert['refid'];
299
		switch ($pconfig['method']) {
300
			case "internal":
301
				if (isset($_POST["keytype"]) && !in_array($_POST["keytype"], $cert_keytypes)) {
302
					$input_errors[] = gettext("Please select a valid Key Type.");
403 303
				}
404
			} else if ($pconfig['method'] == "sign") { // Sign a CSR
405
				$csrid = lookup_cert($pconfig['csrtosign']);
406
				$ca = & lookup_ca($pconfig['catosignwith']);
407

  
408
				// Read the CSR from $config, or if a new one, from the textarea
409
				if ($pconfig['csrtosign'] === "new") {
410
					$csr = $pconfig['csrpaste'];
411
				} else {
412
					$csr = base64_decode($csrid['csr']);
304
				if (isset($_POST["keylen"]) && !in_array($_POST["keylen"], $cert_keylens)) {
305
					$input_errors[] = gettext("Please select a valid Key Length.");
413 306
				}
414
				if (count($altnames)) {
415
					foreach ($altnames as $altname) {
416
						$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
417
					}
418
					$altname_str = implode(",", $altnames_tmp);
307
				if (isset($_POST["ecname"]) && !in_array($_POST["ecname"], $openssl_ecnames)) {
308
					$input_errors[] = gettext("Please select a valid Elliptic Curve Name.");
309
				}
310
				if (!in_array($_POST["digest_alg"], $openssl_digest_algs)) {
311
					$input_errors[] = gettext("Please select a valid Digest Algorithm.");
312
				}
313
				break;
314
			case "external":
315
				if (isset($_POST["csr_keytype"]) && !in_array($_POST["csr_keytype"], $cert_keytypes)) {
316
					$input_errors[] = gettext("Please select a valid Key Type.");
419 317
				}
318
				if (isset($_POST["csr_keylen"]) && !in_array($_POST["csr_keylen"], $cert_keylens)) {
319
					$input_errors[] = gettext("Please select a valid Key Length.");
320
				}
321
				if (isset($_POST["csr_ecname"]) && !in_array($_POST["csr_ecname"], $openssl_ecnames)) {
322
					$input_errors[] = gettext("Please select a valid Elliptic Curve Name.");
323
				}
324
				if (!in_array($_POST["csr_digest_alg"], $openssl_digest_algs)) {
325
					$input_errors[] = gettext("Please select a valid Digest Algorithm.");
326
				}
327
				break;
328
			case "sign":
329
				if (!in_array($_POST["csrsign_digest_alg"], $openssl_digest_algs)) {
330
					$input_errors[] = gettext("Please select a valid Digest Algorithm.");
331
				}
332
				break;
333
			default:
334
				break;
335
		}
336
	}
420 337

  
421
				$n509 = csr_sign($csr, $ca, $pconfig['csrsign_lifetime'], $pconfig['type'], $altname_str, $pconfig['csrsign_digest_alg']);
422

  
423
				if ($n509) {
424
					// Gather the details required to save the new cert
425
					$newcert = array();
426
					$newcert['refid'] = uniqid();
427
					$newcert['caref'] = $pconfig['catosignwith'];
428
					$newcert['descr'] = $pconfig['descr'];
429
					$newcert['type'] = $pconfig['type'];
430
					$newcert['crt'] = base64_encode($n509);
431

  
432
					if ($pconfig['csrtosign'] === "new") {
433
						$newcert['prv'] = base64_encode($pconfig['keypaste']);
434
					} else {
435
						$newcert['prv'] = $csrid['prv'];
436
					}
338
	/* save modifications */
339
	if (!$input_errors) {
437 340

  
438
					// Add it to the config file
439
					$config['cert'][] = $newcert;
440
				}
341
		if ($pconfig['method'] == "existing") {
342
			$cert = lookup_cert($pconfig['certref']);
343
			if ($cert && $a_user) {
344
				$a_user[$userid]['cert'][] = $cert['refid'];
345
			}
346
		} elseif ($pconfig['method'] == "sign") { // Sign a CSR
347
			$csrid = lookup_cert($pconfig['csrtosign']);
348
			$ca = & lookup_ca($pconfig['catosignwith']);
441 349

  
350
			// Read the CSR from $config, or if a new one, from the textarea
351
			if ($pconfig['csrtosign'] === "new") {
352
				$csr = $pconfig['csrpaste'];
442 353
			} else {
443
				$cert = array();
444
				$cert['refid'] = uniqid();
445
				if (isset($id) && $a_cert[$id]) {
446
					$cert = $a_cert[$id];
354
				$csr = base64_decode($csrid['csr']);
355
			}
356
			if (count($altnames)) {
357
				foreach ($altnames as $altname) {
358
					$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
447 359
				}
360
				$altname_str = implode(",", $altnames_tmp);
361
			}
448 362

  
449
				$cert['descr'] = $pconfig['descr'];
363
			$n509 = csr_sign($csr, $ca, $pconfig['csrsign_lifetime'], $pconfig['type'], $altname_str, $pconfig['csrsign_digest_alg']);
450 364

  
451
				$old_err_level = error_reporting(0); /* otherwise openssl_ functions throw warnings directly to a page screwing menu tab */
365
			if ($n509) {
366
				// Gather the details required to save the new cert
367
				$newcert = array();
368
				$newcert['refid'] = uniqid();
369
				$newcert['caref'] = $pconfig['catosignwith'];
370
				$newcert['descr'] = $pconfig['descr'];
371
				$newcert['type'] = $pconfig['type'];
372
				$newcert['crt'] = base64_encode($n509);
452 373

  
453
				if ($pconfig['method'] == "import") {
454
					cert_import($cert, $pconfig['cert'], $pconfig['key']);
374
				if ($pconfig['csrtosign'] === "new") {
375
					$newcert['prv'] = base64_encode($pconfig['keypaste']);
376
				} else {
377
					$newcert['prv'] = $csrid['prv'];
455 378
				}
456 379

  
457
				if ($pconfig['method'] == "internal") {
458
					$dn = array('commonName' => cert_escape_x509_chars($pconfig['dn_commonname']));
459
					if (!empty($pconfig['dn_country'])) {
460
						$dn['countryName'] = $pconfig['dn_country'];
461
					}
462
					if (!empty($pconfig['dn_state'])) {
463
						$dn['stateOrProvinceName'] = cert_escape_x509_chars($pconfig['dn_state']);
464
					}
465
					if (!empty($pconfig['dn_city'])) {
466
						$dn['localityName'] = cert_escape_x509_chars($pconfig['dn_city']);
467
					}
468
					if (!empty($pconfig['dn_organization'])) {
469
						$dn['organizationName'] = cert_escape_x509_chars($pconfig['dn_organization']);
470
					}
471
					if (!empty($pconfig['dn_organizationalunit'])) {
472
						$dn['organizationalUnitName'] = cert_escape_x509_chars($pconfig['dn_organizationalunit']);
473
					}
380
				// Add it to the config file
381
				$config['cert'][] = $newcert;
382
			}
474 383

  
475
					$altnames_tmp = array();
476
					$cn_altname = cert_add_altname_type($pconfig['dn_commonname']);
477
					if (!empty($cn_altname)) {
478
						$altnames_tmp[] = $cn_altname;
479
					}
480
					if (count($altnames)) {
481
						foreach ($altnames as $altname) {
482
							// The CN is added as a SAN automatically, do not add it again.
483
							if ($altname['value'] != $pconfig['dn_commonname']) {
484
								$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
485
							}
486
						}
487
					}
488
					if (!empty($altnames_tmp)) {
489
						$dn['subjectAltName'] = implode(",", $altnames_tmp);
490
					}
384
		} else {
385
			$cert = array();
386
			$cert['refid'] = uniqid();
387
			if (isset($id) && $a_cert[$id]) {
388
				$cert = $a_cert[$id];
389
			}
491 390

  
492
					if (!cert_create($cert, $pconfig['caref'], $pconfig['keylen'], $pconfig['lifetime'], $dn, $pconfig['type'], $pconfig['digest_alg'], $pconfig['keytype'], $pconfig['ecname'])) {
493
						$input_errors = array();
494
						while ($ssl_err = openssl_error_string()) {
495
							if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
496
								array_push($input_errors, "openssl library returns: " . $ssl_err);
497
							}
498
						}
499
					}
500
				}
391
			$cert['descr'] = $pconfig['descr'];
501 392

  
502
				if ($pconfig['method'] == "external") {
503
					$dn = array('commonName' => cert_escape_x509_chars($pconfig['csr_dn_commonname']));
504
					if (!empty($pconfig['csr_dn_country'])) {
505
						$dn['countryName'] = $pconfig['csr_dn_country'];
506
					}
507
					if (!empty($pconfig['csr_dn_state'])) {
508
						$dn['stateOrProvinceName'] = cert_escape_x509_chars($pconfig['csr_dn_state']);
509
					}
510
					if (!empty($pconfig['csr_dn_city'])) {
511
						$dn['localityName'] = cert_escape_x509_chars($pconfig['csr_dn_city']);
512
					}
513
					if (!empty($pconfig['csr_dn_organization'])) {
514
						$dn['organizationName'] = cert_escape_x509_chars($pconfig['csr_dn_organization']);
515
					}
516
					if (!empty($pconfig['csr_dn_organizationalunit'])) {
517
						$dn['organizationalUnitName'] = cert_escape_x509_chars($pconfig['csr_dn_organizationalunit']);
518
					}
393
			$old_err_level = error_reporting(0); /* otherwise openssl_ functions throw warnings directly to a page breaking menu tabs */
519 394

  
520
					$altnames_tmp = array();
521
					$cn_altname = cert_add_altname_type($pconfig['csr_dn_commonname']);
522
					if (!empty($cn_altname)) {
523
						$altnames_tmp[] = $cn_altname;
524
					}
525
					if (count($altnames)) {
526
						foreach ($altnames as $altname) {
527
							// The CN is added as a SAN automatically, do not add it again.
528
							if ($altname['value'] != $pconfig['csr_dn_commonname']) {
529
								$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
530
							}
395
			if ($pconfig['method'] == "import") {
396
				cert_import($cert, $pconfig['cert'], $pconfig['key']);
397
			}
398

  
399
			if ($pconfig['method'] == "internal") {
400
				$dn = array('commonName' => cert_escape_x509_chars($pconfig['dn_commonname']));
401
				if (!empty($pconfig['dn_country'])) {
402
					$dn['countryName'] = $pconfig['dn_country'];
403
				}
404
				if (!empty($pconfig['dn_state'])) {
405
					$dn['stateOrProvinceName'] = cert_escape_x509_chars($pconfig['dn_state']);
406
				}
407
				if (!empty($pconfig['dn_city'])) {
408
					$dn['localityName'] = cert_escape_x509_chars($pconfig['dn_city']);
409
				}
410
				if (!empty($pconfig['dn_organization'])) {
411
					$dn['organizationName'] = cert_escape_x509_chars($pconfig['dn_organization']);
412
				}
413
				if (!empty($pconfig['dn_organizationalunit'])) {
414
					$dn['organizationalUnitName'] = cert_escape_x509_chars($pconfig['dn_organizationalunit']);
415
				}
416

  
417
				$altnames_tmp = array();
418
				$cn_altname = cert_add_altname_type($pconfig['dn_commonname']);
419
				if (!empty($cn_altname)) {
420
					$altnames_tmp[] = $cn_altname;
421
				}
422
				if (count($altnames)) {
423
					foreach ($altnames as $altname) {
424
						// The CN is added as a SAN automatically, do not add it again.
425
						if ($altname['value'] != $pconfig['dn_commonname']) {
426
							$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
531 427
						}
532 428
					}
533
					if (!empty($altnames_tmp)) {
534
						$dn['subjectAltName'] = implode(",", $altnames_tmp);
535
					}
429
				}
430
				if (!empty($altnames_tmp)) {
431
					$dn['subjectAltName'] = implode(",", $altnames_tmp);
432
				}
536 433

  
537
					if (!csr_generate($cert, $pconfig['csr_keylen'], $dn, $pconfig['type'], $pconfig['csr_digest_alg'], $pconfig['csr_keytype'], $pconfig['csr_ecname'])) {
538
						$input_errors = array();
539
						while ($ssl_err = openssl_error_string()) {
540
							if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
541
								array_push($input_errors, "openssl library returns: " . $ssl_err);
542
							}
434
				if (!cert_create($cert, $pconfig['caref'], $pconfig['keylen'], $pconfig['lifetime'], $dn, $pconfig['type'], $pconfig['digest_alg'], $pconfig['keytype'], $pconfig['ecname'])) {
435
					$input_errors = array();
436
					while ($ssl_err = openssl_error_string()) {
437
						if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
438
							$input_errors[] = sprintf(gettext("OpenSSL Library Error: %s"), $ssl_err);
543 439
						}
544 440
					}
545 441
				}
442
			}
546 443

  
547
				error_reporting($old_err_level);
444
			if ($pconfig['method'] == "external") {
445
				$dn = array('commonName' => cert_escape_x509_chars($pconfig['csr_dn_commonname']));
446
				if (!empty($pconfig['csr_dn_country'])) {
447
					$dn['countryName'] = $pconfig['csr_dn_country'];
448
				}
449
				if (!empty($pconfig['csr_dn_state'])) {
450
					$dn['stateOrProvinceName'] = cert_escape_x509_chars($pconfig['csr_dn_state']);
451
				}
452
				if (!empty($pconfig['csr_dn_city'])) {
453
					$dn['localityName'] = cert_escape_x509_chars($pconfig['csr_dn_city']);
454
				}
455
				if (!empty($pconfig['csr_dn_organization'])) {
456
					$dn['organizationName'] = cert_escape_x509_chars($pconfig['csr_dn_organization']);
457
				}
458
				if (!empty($pconfig['csr_dn_organizationalunit'])) {
459
					$dn['organizationalUnitName'] = cert_escape_x509_chars($pconfig['csr_dn_organizationalunit']);
460
				}
548 461

  
549
				if (isset($id) && $a_cert[$id]) {
550
					$a_cert[$id] = $cert;
551
				} else {
552
					$a_cert[] = $cert;
462
				$altnames_tmp = array();
463
				$cn_altname = cert_add_altname_type($pconfig['csr_dn_commonname']);
464
				if (!empty($cn_altname)) {
465
					$altnames_tmp[] = $cn_altname;
466
				}
467
				if (count($altnames)) {
468
					foreach ($altnames as $altname) {
469
						// The CN is added as a SAN automatically, do not add it again.
470
						if ($altname['value'] != $pconfig['csr_dn_commonname']) {
471
							$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
472
						}
473
					}
474
				}
475
				if (!empty($altnames_tmp)) {
476
					$dn['subjectAltName'] = implode(",", $altnames_tmp);
553 477
				}
554 478

  
555
				if (isset($a_user) && isset($userid)) {
556
					$a_user[$userid]['cert'][] = $cert['refid'];
479
				if (!csr_generate($cert, $pconfig['csr_keylen'], $dn, $pconfig['type'], $pconfig['csr_digest_alg'], $pconfig['csr_keytype'], $pconfig['csr_ecname'])) {
480
					$input_errors = array();
481
					while ($ssl_err = openssl_error_string()) {
482
						if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
483
							$input_errors[] = sprintf(gettext("OpenSSL Library Error: %s"), $ssl_err);
484
						}
485
					}
557 486
				}
558 487
			}
559 488

  
560
			if (!$input_errors) {
561
				write_config();
489
			error_reporting($old_err_level);
490

  
491
			if (isset($id) && $a_cert[$id]) {
492
				$a_cert[$id] = $cert;
493
			} else {
494
				$a_cert[] = $cert;
562 495
			}
563 496

  
564
			if ((isset($userid) && is_numeric($userid)) && !$input_errors) {
565
				post_redirect("system_usermanager.php", array('act' => 'edit', 'userid' => $userid));
566
				exit;
497
			if (isset($a_user) && isset($userid)) {
498
				$a_user[$userid]['cert'][] = $cert['refid'];
567 499
			}
568 500
		}
569
	}
570

  
571
	if ($_POST['save'] == gettext("Update")) {
572
		unset($input_errors);
573
		$pconfig = $_POST;
574

  
575
		/* input validation */
576
		$reqdfields = explode(" ", "descr cert");
577
		$reqdfieldsn = array(
578
			gettext("Descriptive name"),
579
			gettext("Final Certificate data"));
580 501

  
581
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
582

  
583
		if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
584
			array_push($input_errors, "The field 'Descriptive Name' contains invalid characters.");
502
		if (!$input_errors) {
503
			write_config();
585 504
		}
586 505

  
587
//		old way
588
		/* make sure this csr and certificate subjects match */
589
//		$subj_csr = csr_get_subject($pconfig['csr'], false);
590
//		$subj_cert = cert_get_subject($pconfig['cert'], false);
591
//
592
//		if (!isset($_POST['ignoresubjectmismatch']) && !($_POST['ignoresubjectmismatch'] == "yes")) {
593
//			if (strcmp($subj_csr, $subj_cert)) {
594
//				$input_errors[] = sprintf(gettext("The certificate subject '%s' does not match the signing request subject."), $subj_cert);
595
//				$subject_mismatch = true;
596
//			}
597
//		}
598
		$mod_csr = cert_get_publickey($pconfig['csr'], false, 'csr');
599
		$mod_cert = cert_get_publickey($pconfig['cert'], false);
600

  
601
		if (strcmp($mod_csr, $mod_cert)) {
602
			// simply: if the moduli don't match, then the private key and public key won't match
603
			$input_errors[] = sprintf(gettext("The certificate public key does not match the signing request public key."), $subj_cert);
604
			$subject_mismatch = true;
506
		if ((isset($userid) && is_numeric($userid)) && !$input_errors) {
507
			post_redirect("system_usermanager.php", array('act' => 'edit', 'userid' => $userid));
508
			exit;
605 509
		}
510
	}
511
} elseif ($_POST['save'] == gettext("Update")) {
512
	/* Updating a certificate signing request */
513
	unset($input_errors);
514
	$pconfig = $_POST;
606 515

  
607
		/* save modifications */
608
		if (!$input_errors) {
609

  
610
			$cert = $a_cert[$id];
516
	/* input validation */
517
	$reqdfields = explode(" ", "descr cert");
518
	$reqdfieldsn = array(
519
		gettext("Descriptive name"),
520
		gettext("Final Certificate data"));
611 521

  
612
			$cert['descr'] = $pconfig['descr'];
522
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
613 523

  
614
			csr_complete($cert, $pconfig['cert']);
524
	if (preg_match("/[\?\>\<\&\/\\\"\']/", $_POST['descr'])) {
525
		$input_errors[] = gettext("The field 'Descriptive Name' contains invalid characters.");
526
	}
615 527

  
616
			$a_cert[$id] = $cert;
528
	$mod_csr = cert_get_publickey($pconfig['csr'], false, 'csr');
529
	$mod_cert = cert_get_publickey($pconfig['cert'], false);
617 530

  
618
			write_config();
531
	if (strcmp($mod_csr, $mod_cert)) {
532
		// simply: if the moduli don't match, then the private key and public key won't match
533
		$input_errors[] = gettext("The certificate public key does not match the signing request public key.");
534
		$subject_mismatch = true;
535
	}
619 536

  
620
			pfSenseHeader("system_certmanager.php");
621
		}
537
	/* save modifications */
538
	if (!$input_errors) {
539
		$cert = $a_cert[$id];
540
		$cert['descr'] = $pconfig['descr'];
541
		csr_complete($cert, $pconfig['cert']);
542
		$a_cert[$id] = $cert;
543
		write_config();
544
		pfSenseHeader("system_certmanager.php");
622 545
	}
623 546
}
624 547

  
625 548
$pgtitle = array(gettext("System"), gettext("Certificate Manager"), gettext("Certificates"));
626 549
$pglinks = array("", "system_camanager.php", "system_certmanager.php");
627 550

  
628
if (($act == "new" || ($_POST['save'] == gettext("Save") && $input_errors)) || ($act == "csr" || ($_POST['save'] == gettext("Update") && $input_errors))) {
551
if (($act == "new" || ($_POST['save'] == gettext("Save") && $input_errors)) ||
552
    ($act == "csr" || ($_POST['save'] == gettext("Update") && $input_errors))) {
629 553
	$pgtitle[] = gettext('Edit');
630 554
	$pglinks[] = "@self";
631 555
}
......
1128 1052

  
1129 1053
	print $form;
1130 1054

  
1131
} else if ($act == "csr" || (($_POST['save'] == gettext("Update")) && $input_errors)) {
1055
} elseif ($act == "csr" || (($_POST['save'] == gettext("Update")) && $input_errors)) {
1132 1056
	$form = new Form(false);
1133 1057
	$form->setAction('system_certmanager.php?act=csr');
1134 1058

  
src/usr/local/www/system_crlmanager.php
70 70
	$thiscrl =& lookup_crl($id);
71 71
}
72 72

  
73
// If we were given an invalid crlref in the id, no sense in continuing as it would only cause errors.
74
if (!$thiscrl && (($act != "") && ($act != "new"))) {
75
	pfSenseHeader("system_crlmanager.php");
73
/* Actions other than 'new' require a CRL to act upon.
74
 * 'del' action must be submitted via POST. */
75
if ((!empty($act) &&
76
    ($act != 'new') &&
77
    !$thiscrl) ||
78
    (($act == 'del') && empty($_POST))) {
79
	pfSenseHeader("system_camanager.php");
76 80
	$act="";
77 81
	$savemsg = gettext("Invalid CRL reference.");
78 82
	$class = "danger";
79 83
}
80 84

  
81
if ($_POST['act'] == "del") {
82
	$name = htmlspecialchars($thiscrl['descr']);
83
	if (crl_in_use($id)) {
84
		$savemsg = sprintf(gettext("Certificate Revocation List %s is in use and cannot be deleted."), $name);
85
		$class = "danger";
86
	} else {
87
		foreach ($a_crl as $cid => $acrl) {
88
			if ($acrl['refid'] == $thiscrl['refid']) {
89
				unset($a_crl[$cid]);
85
switch ($act) {
86
	case 'del':
87
		$name = htmlspecialchars($thiscrl['descr']);
88
		if (crl_in_use($id)) {
89
			$savemsg = sprintf(gettext("Certificate Revocation List %s is in use and cannot be deleted."), $name);
90
			$class = "danger";
91
		} else {
92
			foreach ($a_crl as $cid => $acrl) {
93
				if ($acrl['refid'] == $thiscrl['refid']) {
94
					unset($a_crl[$cid]);
95
				}
90 96
			}
97
			write_config("Deleted CRL {$name}.");
98
			$savemsg = sprintf(gettext("Certificate Revocation List %s successfully deleted."), $name);
99
			$class = "success";
91 100
		}
92
		write_config("Deleted CRL {$name}.");
93
		$savemsg = sprintf(gettext("Certificate Revocation List %s successfully deleted."), $name);
94
		$class = "success";
95
	}
96
}
97

  
98
if ($act == "new") {
99
	$pconfig['method'] = $_REQUEST['method'];
100
	$pconfig['caref'] = $_REQUEST['caref'];
101
	$pconfig['lifetime'] = $default_lifetime;
102
	$pconfig['serial'] = "0";
103
	$crlca =& lookup_ca($pconfig['caref']);
104
	if (!$crlca) {
105
		$input_errors[] = gettext('Invalid CA');
106
		unset($act);
107
	}
108
}
109

  
110
if ($act == "exp") {
111
	crl_update($thiscrl);
112
	$exp_name = urlencode("{$thiscrl['descr']}.crl");
113
	$exp_data = base64_decode($thiscrl['text']);
114
	$exp_size = strlen($exp_data);
115

  
116
	header("Content-Type: application/octet-stream");
117
	header("Content-Disposition: attachment; filename={$exp_name}");
118
	header("Content-Length: $exp_size");
119
	echo $exp_data;
120
	exit;
121
}
122

  
123
if ($act == "addcert") {
124
	unset($input_errors);
125
	$pconfig = $_REQUEST;
126
	$revoke_list = array();
127

  
128
	if (!$pconfig['crlref'] || (!$pconfig['certref'] && !$pconfig['revokeserial'])) {
129
		pfSenseHeader("system_crlmanager.php");
130
		exit;
131
	}
132

  
133
	// certref, crlref
134
	$crl =& lookup_crl($pconfig['crlref']);
135
	if (!is_array($pconfig['certref'])) {
136
		$pconfig['certref'] = array();
137
	}
138

  
139
	if (empty($pconfig['certref']) && empty($pconfig['revokeserial'])) {
140
		$input_errors[] = gettext("Select one or more certificates or enter a serial number to revoke.");
141
	}
142
	if (!is_crl_internal($crl)) {
143
		$input_errors[] = gettext("Cannot revoke certificates for an imported/external CRL.");
144
	}
145

  
146
	foreach ($pconfig['certref'] as $rcert) {
147
		$cert = lookup_cert($rcert);
148
		if ($crl['caref'] == $cert['caref']) {
149
			$revoke_list[] = $cert;
150
		} else {
151
			$input_errors[] = gettext("CA mismatch between the Certificate and CRL. Unable to Revoke.");
101
		break;
102
	case 'new':
103
		$pconfig['method'] = $_REQUEST['method'];
104
		$pconfig['caref'] = $_REQUEST['caref'];
105
		$pconfig['lifetime'] = $default_lifetime;
106
		$pconfig['serial'] = "0";
107
		$crlca =& lookup_ca($pconfig['caref']);
108
		if (!$crlca) {
109
			$input_errors[] = gettext('Invalid CA');
110
			unset($act);
152 111
		}
153
	}
154

  
155
	foreach (explode(' ', $pconfig['revokeserial']) as $serial) {
156
		if (empty($serial)) {
157
			continue;
112
		break;
113
	case 'addcert':
114
		unset($input_errors);
115
		$pconfig = $_REQUEST;
116
		$revoke_list = array();
117
		if (!$pconfig['crlref'] || (!$pconfig['certref'] && !$pconfig['revokeserial'])) {
118
			pfSenseHeader("system_crlmanager.php");
119
			exit;
158 120
		}
159
		$vserial = cert_validate_serial($serial, true, true);
160
		if ($vserial != null) {
161
			$revoke_list[] = $vserial;
121
		$crl =& lookup_crl($pconfig['crlref']);
122
		if (!is_array($pconfig['certref'])) {
123
			$pconfig['certref'] = array();
124
		}
125
		if (empty($pconfig['certref']) && empty($pconfig['revokeserial'])) {
126
			$input_errors[] = gettext("Select one or more certificates or enter a serial number to revoke.");
127
		}
128
		if (!is_crl_internal($crl)) {
129
			$input_errors[] = gettext("Cannot revoke certificates for an imported/external CRL.");
130
		}
131
		foreach ($pconfig['certref'] as $rcert) {
132
			$cert = lookup_cert($rcert);
133
			if ($crl['caref'] == $cert['caref']) {
134
				$revoke_list[] = $cert;
135
			} else {
136
				$input_errors[] = gettext("CA mismatch between the Certificate and CRL. Unable to Revoke.");
137
			}
138
		}
139
		foreach (explode(' ', $pconfig['revokeserial']) as $serial) {
140
			if (empty($serial)) {
141
				continue;
142
			}
143
			$vserial = cert_validate_serial($serial, true, true);
144
			if ($vserial != null) {
145
				$revoke_list[] = $vserial;
146
			} else {
147
				$input_errors[] = gettext("Invalid serial in list (Must be ASN.1 integer compatible decimal or hex string).");
148
			}
149
		}
150
		if (!$input_errors) {
151
			$reason = (empty($pconfig['crlreason'])) ? 0 : $pconfig['crlreason'];
152
			foreach ($revoke_list as $cert) {
153
				cert_revoke($cert, $crl, $reason);
154
			}
155
			// refresh IPsec and OpenVPN CRLs
156
			openvpn_refresh_crls();
157
			vpn_ipsec_configure();
158
			write_config("Revoked certificate(s) in CRL {$crl['descr']}.");
159
			pfSenseHeader("system_crlmanager.php");
160
			exit;
162 161
		} else {
163
			$input_errors[] = gettext("Invalid serial in list (Must be ASN.1 integer compatible decimal or hex string).");
162
			$act = 'edit';
164 163
		}
165
	}
166

  
167
	if (!$input_errors) {
168
		$reason = (empty($pconfig['crlreason'])) ? 0 : $pconfig['crlreason'];
169

  
170
		foreach ($revoke_list as $cert) {
171
			cert_revoke($cert, $crl, $reason);
164
		break;
165
	case 'delcert':
166
		if (!is_array($thiscrl['cert'])) {
167
			pfSenseHeader("system_crlmanager.php");
168
			exit;
172 169
		}
173

  
174
		// refresh IPsec and OpenVPN CRLs
175
		openvpn_refresh_crls();
176
		vpn_ipsec_configure();
177
		write_config("Revoked certificate(s) in CRL {$crl['descr']}.");
178
		pfSenseHeader("system_crlmanager.php");
179
		exit;
180
	} else {
181
		$act = 'edit';
182
	}
183
}
184

  
185
if ($act == "delcert") {
186
	if (!is_array($thiscrl['cert'])) {
187
		pfSenseHeader("system_crlmanager.php");
188
		exit;
189
	}
190
	$found = false;
191
	foreach ($thiscrl['cert'] as $acert) {
192
		if ($acert['refid'] == $_REQUEST['certref']) {
193
			$found = true;
194
			$thiscert = $acert;
170
		$found = false;
171
		foreach ($thiscrl['cert'] as $acert) {
172
			if ($acert['refid'] == $_REQUEST['certref']) {
173
				$found = true;
174
				$thiscert = $acert;
175
			}
195 176
		}
196
	}
197
	if (!$found) {
198
		pfSenseHeader("system_crlmanager.php");
199
		exit;
200
	}
201
	$certname = htmlspecialchars($thiscert['descr']);
202
	$crlname = htmlspecialchars($thiscrl['descr']);
203
	if (cert_unrevoke($thiscert, $thiscrl)) {
204
		$savemsg = sprintf(gettext('Deleted Certificate %1$s from CRL %2$s.'), $certname, $crlname);
205
		$class = "success";
206
		// refresh IPsec and OpenVPN CRLs
207
		openvpn_refresh_crls();
208
		vpn_ipsec_configure();
209
		write_config($savemsg);
210
	} else {
211
		$savemsg = sprintf(gettext('Failed to delete Certificate %1$s from CRL %2$s.'), $certname, $crlname);
212
		$class = "danger";
213
	}
214
	$act="edit";
177
		if (!$found) {
178
			pfSenseHeader("system_crlmanager.php");
179
			exit;
180
		}
181
		$certname = htmlspecialchars($thiscert['descr']);
182
		$crlname = htmlspecialchars($thiscrl['descr']);
183
		if (cert_unrevoke($thiscert, $thiscrl)) {
184
			$savemsg = sprintf(gettext('Deleted Certificate %1$s from CRL %2$s.'), $certname, $crlname);
185
			$class = "success";
186
			// refresh IPsec and OpenVPN CRLs
187
			openvpn_refresh_crls();
188
			vpn_ipsec_configure();
189
			write_config($savemsg);
190
		} else {
191
			$savemsg = sprintf(gettext('Failed to delete Certificate %1$s from CRL %2$s.'), $certname, $crlname);
192
			$class = "danger";
193
		}
194
		$act="edit";
195
		break;
196
	case 'exp':
197
		/* Exporting the CRL contents*/
198
		crl_update($thiscrl);
199
		send_user_download('data', base64_decode($thiscrl['text']), "{$thiscrl['descr']}.crl");
200
		break;
201
	default:
202
		break;
215 203
}
216 204

  
217 205
if ($_POST['save']) {

Also available in: Unified diff