Project

General

Profile

Download (12.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
	Copyright (C) 2008 Shrew Soft Inc
5
	Copyright (C) 2010 Jim Pingle <jimp@pfsense.org>
6
	All rights reserved.
7

    
8
        Redistribution and use in source and binary forms, with or without
9
        modification, are permitted provided that the following conditions are met:
10

    
11
        1. Redistributions of source code must retain the above copyright notice,
12
           this list of conditions and the following disclaimer.
13

    
14
        2. Redistributions in binary form must reproduce the above copyright
15
           notice, this list of conditions and the following disclaimer in the
16
           documentation and/or other materials provided with the distribution.
17

    
18
        THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
        INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
        AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21
        AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22
        OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
        SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
        INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
        CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
        ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
        POSSIBILITY OF SUCH DAMAGE.
28

    
29
		DISABLE_PHP_LINT_CHECKING
30
		pfSense_MODULE:	certificate_managaer
31
*/
32

    
33
require_once("functions.inc");
34

    
35
function & lookup_ca($refid) {
36
	global $config;
37

    
38
	if (is_array($config['ca']))
39
		foreach ($config['ca'] as & $ca)
40
			if ($ca['refid'] == $refid)
41
				return $ca;
42

    
43
	return false;
44
}
45

    
46
function & lookup_ca_by_subject($subject) {
47
	global $config;
48

    
49
	if (is_array($config['ca']))
50
		foreach ($config['ca'] as & $ca)
51
		{
52
			$ca_subject = cert_get_subject($ca['crt']);
53
			if ($ca_subject == $subject)
54
				return $ca;
55
		}
56

    
57
	return false;
58
}
59

    
60
function & lookup_cert($refid) {
61
	global $config;
62

    
63
	if (is_array($config['cert']))
64
		foreach ($config['cert'] as & $cert)
65
			if ($cert['refid'] == $refid)
66
				return $cert;
67

    
68
	return false;
69
}
70

    
71
function & lookup_cert_by_name($name) {
72
	global $config;
73
	if (is_array($config['cert']))
74
		foreach ($config['cert'] as & $cert)
75
			if ($cert['name'] == $name)
76
				return $cert;
77
}
78

    
79
function & lookup_crl($refid) {
80
	global $config;
81

    
82
	if (is_array($config['crl']))
83
		foreach ($config['crl'] as & $crl)
84
			if ($crl['refid'] == $refid)
85
				return $crl;
86

    
87
	return false;
88
}
89

    
90
function ca_chain_array(& $cert) {
91
	if($cert['caref']) {
92
		$chain = array();
93
		$crt =& lookup_ca($cert['caref']);
94
		$chain[] = $crt;
95
		while ($crt) {
96
			$caref = $crt['caref'];
97
			if($caref)
98
				$crt =& lookup_ca($caref);
99
			else
100
				$crt = false;
101
			if($crt)
102
				$chain[] = $crt;
103
		}
104
		return $chain;
105
	}
106
	return false;
107
}
108

    
109
function ca_chain(& $cert) {
110
	if($cert['caref']) {
111
		$ca = "";
112
		$cas = ca_chain_array($cert);
113
		if (is_array($cas))
114
			foreach ($cas as & $ca_cert)
115
			{
116
				$ca .= base64_decode($ca_cert['crt']);
117
				$ca .= "\n";
118
			}
119
		return $ca;
120
	}
121
	return "";
122
}
123

    
124
function ca_import(& $ca, $str, $key="") {
125
	global $config;
126

    
127
	$ca['crt'] = base64_encode($str);
128
	if (!empty($key))
129
		$ca['prv'] = base64_encode($key);
130

    
131
	$subject = cert_get_subject($str, false);
132
	$issuer = cert_get_issuer($str, false);
133
	
134
	// Find my issuer unless self-signed
135
	if($issuer <> $subject) {
136
		$issuer_crt =& lookup_ca_by_subject($issuer);
137
		if($issuer_crt)
138
			$ca['caref'] = $issuer_crt['refid'];
139
	}
140

    
141
	/* Correct if child certificate was loaded first */
142
	if (is_array($config['ca']))
143
		foreach ($config['ca'] as & $oca)
144
		{
145
			$issuer = cert_get_issuer($oca['crt']);
146
			if($ca['refid']<>$oca['refid'] && $issuer==$subject)
147
				$oca['caref'] = $ca['refid'];
148
		}
149
	if (is_array($config['cert']))
150
		foreach ($config['cert'] as & $cert)
151
		{
152
			$issuer = cert_get_issuer($cert['crt']);
153
			if($issuer==$subject)
154
				$cert['caref'] = $ca['refid'];
155
		}
156
	return true;
157
}
158

    
159
function ca_create(& $ca, $keylen, $lifetime, $dn) {
160

    
161
	$args = array(
162
		"digest_alg" => "sha1",
163
		"private_key_bits" => (int)$keylen,
164
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
165
		"encrypt_key" => false);
166

    
167
	// generate a new key pair
168
	$res_key = openssl_pkey_new();
169

    
170
	// generate a certificate signing request
171
	$res_csr = openssl_csr_new($dn, $res_key, $args);
172

    
173
	// self sign the certificate
174
	$res_crt = openssl_csr_sign($res_csr, null, $res_key, $lifetime, $args);
175

    
176
	// export our certificate data
177
	openssl_pkey_export($res_key, $str_key);
178
	openssl_x509_export($res_crt, $str_crt);
179

    
180
	// return our ca information
181
	$ca['crt'] = base64_encode($str_crt);
182
	$ca['prv'] = base64_encode($str_key);
183
	$ca['serial'] = 0;
184

    
185
	return true;
186
}
187

    
188
function cert_import(& $cert, $crt_str, $key_str) {
189

    
190
	$cert['crt'] = base64_encode($crt_str);
191
	$cert['prv'] = base64_encode($key_str);
192

    
193
	$subject = cert_get_subject($crt_str, false);
194
	$issuer = cert_get_issuer($crt_str, false);
195
	
196
	// Find my issuer unless self-signed
197
	if($issuer <> $subject) {
198
		$issuer_crt =& lookup_ca_by_subject($issuer);
199
		if($issuer_crt)
200
			$cert['caref'] = $issuer_crt['refid'];
201
	}
202
	return true;
203
}
204

    
205
function cert_create(& $cert, $caref, $keylen, $lifetime, $dn) {
206

    
207
	$ca =& lookup_ca($caref);
208
	if (!$ca)
209
		return false;
210

    
211
	$ca_str_crt = base64_decode($ca['crt']);
212
	$ca_str_key = base64_decode($ca['prv']);
213
	$ca_res_crt = openssl_x509_read($ca_str_crt);
214
	$ca_res_key = openssl_pkey_get_private(array(0 => $ca_str_key, 1 => ""));
215
	$ca_serial = ++$ca['serial'];
216

    
217
	$args = array(
218
		"digest_alg" => "sha1",
219
		"private_key_bits" => (int)$keylen,
220
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
221
		"encrypt_key" => false);
222

    
223
	// generate a new key pair
224
	$res_key = openssl_pkey_new();
225

    
226
	// generate a certificate signing request
227
	$res_csr = openssl_csr_new($dn, $res_key, $args);
228

    
229
	// self sign the certificate
230
	$res_crt = openssl_csr_sign($res_csr, $ca_res_crt, $ca_res_key, $lifetime,
231
				 $args, $ca_serial);
232

    
233
	// export our certificate data
234
	openssl_pkey_export($res_key, $str_key);
235
	openssl_x509_export($res_crt, $str_crt);
236

    
237
	// return our certificate information
238
	$cert['caref'] = $caref;
239
	$cert['crt'] = base64_encode($str_crt);
240
	$cert['prv'] = base64_encode($str_key);
241

    
242
	return true;
243
}
244

    
245
function csr_generate(& $cert, $keylen, $dn) {
246

    
247
	$args = array(
248
		"digest_alg" => "sha1",
249
		"private_key_bits" => (int)$keylen,
250
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
251
		"encrypt_key" => false);
252

    
253
	// generate a new key pair
254
	$res_key = openssl_pkey_new();
255

    
256
	// generate a certificate signing request
257
	$res_csr = openssl_csr_new($dn, $res_key, $args);
258

    
259
	// export our request data
260
	openssl_pkey_export($res_key, $str_key);
261
	openssl_csr_export($res_csr, $str_csr);
262

    
263
	// return our request information
264
	$cert['csr'] = base64_encode($str_csr);
265
	$cert['prv'] = base64_encode($str_key);
266

    
267
	return true;
268
}
269

    
270
function csr_complete(& $cert, $str_crt) {
271

    
272
	// return our request information
273
	$cert['crt'] = base64_encode($str_crt);
274
	unset($cert['csr']);
275

    
276
	return true;
277
}
278

    
279
function csr_get_subject($str_crt, $decode = true) {
280

    
281
	if ($decode)
282
		$str_crt = base64_decode($str_crt);
283

    
284
	$components = openssl_csr_get_subject($str_crt);
285

    
286
	if (!is_array($components))
287
		return "unknown";
288

    
289
	foreach ($components as $a => $v) {
290
		if (!strlen($subject))
291
			$subject = "{$a}={$v}";
292
		else
293
			$subject = "{$a}={$v}, {$subject}";
294
	}
295

    
296
	return $subject;
297
}
298

    
299
function cert_get_subject($str_crt, $decode = true) {
300

    
301
	if ($decode)
302
		$str_crt = base64_decode($str_crt);
303

    
304
	$inf_crt = openssl_x509_parse($str_crt);
305
	$components = $inf_crt['subject'];
306

    
307
	if (!is_array($components))
308
		return "unknown";
309

    
310
	foreach ($components as $a => $v) {
311
		if (!strlen($subject))
312
			$subject = "{$a}={$v}";
313
		else
314
			$subject = "{$a}={$v}, {$subject}";
315
	}
316

    
317
	return $subject;
318
}
319

    
320
function cert_get_subject_array($crt) {
321
	$str_crt = base64_decode($crt);
322
	$inf_crt = openssl_x509_parse($str_crt);
323
	$components = $inf_crt['subject'];
324
	$subject_array = array();
325

    
326
	foreach($components as $a => $v)
327
		$subject_array[] = array('a' => $a, 'v' => $v);
328

    
329
	return $subject_array;
330
}
331

    
332
function cert_get_subject_hash($crt) {
333
	$str_crt = base64_decode($crt);
334
	$inf_crt = openssl_x509_parse($str_crt);
335
	return $inf_crt['subject'];
336
}
337

    
338
function cert_get_issuer($str_crt, $decode = true) {
339

    
340
	if ($decode)
341
		$str_crt = base64_decode($str_crt);
342

    
343
	$inf_crt = openssl_x509_parse($str_crt);
344
	$components = $inf_crt['issuer'];
345
	
346
	if (!is_array($components))
347
		return "unknown";
348
	foreach ($components as $a => $v) {
349
		if (!strlen($issuer))
350
			$issuer = "{$a}={$v}";
351
		else
352
			$issuer = "{$a}={$v}, {$issuer}";
353
	}
354

    
355
	return $issuer;
356
}
357

    
358
function is_user_cert($certref) {
359
	global $config;
360
	if (!is_array($config['system']['user']))
361
		return;
362
	foreach ($config['system']['user'] as $user) {
363
		if (!is_array($user['cert']))
364
			continue;
365
		foreach ($user['cert'] as $cert) {
366
			if ($certref == $cert)
367
				return true;
368
		}
369
	}
370
	return false;
371
}
372

    
373
function is_openvpn_server_cert($certref) {
374
	global $config;
375
	if (!is_array($config['openvpn']['openvpn-server']))
376
		return;
377
	foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
378
		if ($ovpns['certref'] == $certref)
379
			return true;
380
	}
381
	return false;
382
}
383

    
384
function is_openvpn_client_cert($certref) {
385
	global $config;
386
	if (!is_array($config['openvpn']['openvpn-client']))
387
		return;
388
	foreach ($config['openvpn']['openvpn-client'] as $ovpnc) {
389
		if ($ovpnc['certref'] == $certref)
390
			return true;
391
	}
392
	return false;
393
}
394

    
395
function is_ipsec_cert($certref) {
396
	global $config;
397
	if (!is_array($config['ipsec']['phase1']))
398
		return;
399
	foreach ($config['ipsec']['phase1'] as $ipsec) {
400
		if ($ipsec['certref'] == $certref)
401
			return true;
402
	}
403
	return false;
404
}
405

    
406
function is_webgui_cert($certref) {
407
	global $config;
408
	if ($config['system']['webgui']['ssl-certref'] == $certref)
409
		return true;
410
}
411

    
412
function cert_in_use($certref) {
413
	return (is_webgui_cert($certref) ||
414
		is_user_cert($certref) ||
415
		is_openvpn_server_cert($certref) ||
416
		is_openvpn_client_cert($certref) ||
417
		is_ipsec_cert($certref));
418
}
419

    
420
/*
421
CRL code is a *WORK IN PROGRESS* do not try to use these functions yet.
422

    
423
OpenSSL CRL status code constants.
424
OCSP_REVOKED_STATUS_NOSTATUS
425
OCSP_REVOKED_STATUS_UNSPECIFIED
426
OCSP_REVOKED_STATUS_KEYCOMPROMISE
427
OCSP_REVOKED_STATUS_CACOMPROMISE
428
OCSP_REVOKED_STATUS_AFFILIATIONCHANGED
429
OCSP_REVOKED_STATUS_SUPERSEDED
430
OCSP_REVOKED_STATUS_CESSATIONOFOPERATION
431
OCSP_REVOKED_STATUS_CERTIFICATEHOLD
432
OCSP_REVOKED_STATUS_REMOVEFROMCRL
433
*/
434

    
435
$openssl_crl_status = array(
436
	OCSP_REVOKED_STATUS_NOSTATUS              => "No Status (default)",
437
	OCSP_REVOKED_STATUS_UNSPECIFIED           => "Unspecified",
438
	OCSP_REVOKED_STATUS_KEYCOMPROMISE         => "Key Compromise",
439
	OCSP_REVOKED_STATUS_CACOMPROMISE          => "CA Compromise",
440
	OCSP_REVOKED_STATUS_AFFILIATIONCHANGED    => "Affiliation Changed",
441
	OCSP_REVOKED_STATUS_SUPERSEDED            => "Superseded",
442
	OCSP_REVOKED_STATUS_CESSATIONOFOPERATION  => "Cessation of Operation",
443
	OCSP_REVOKED_STATUS_CERTIFICATEHOLD       => "Certificate Hold",
444
	OCSP_REVOKED_STATUS_REMOVEFROMCRL         => "Remove from CRL"
445
);
446

    
447
function crl_create(& $crl, $caref, $name, $serial=0, $lifetime=9999) {
448
	global $config;
449
	$ca =& lookup_ca($caref);
450
	if (!$ca)
451
		return false;
452
	$crl['name'] = $name;
453
	$crl['caref'] = $caref;
454
	$crl['serial'] = $serial;
455
	$crl['lifetime'] = $lifetime;
456
	$crl['cert'] = array();
457
	$crl_res = crl_update($crl);
458
	$config['crl'][] = $crl;
459
	return $crl_res;
460
}
461

    
462
function crl_update(& $crl) {
463
	global $config;
464
	$ca =& lookup_ca($crl['caref']);
465
	if (!$ca)
466
		return false;
467
	$crl['serial']++;
468
	$ca_str_crt = base64_decode($ca['crt']);
469
	$ca_str_key = base64_decode($ca['prv']);
470
	$crl_res = openssl_crl_new($ca_str_crt, $crl['serial'], $crl['lifetime']);
471
	foreach ($crl['cert'] as $cert) {
472
		openssl_crl_revoke_cert($crl_res, base64_decode($cert["crt"]), $cert["revoke_time"], $cert["reason"]);
473
	}
474
	openssl_crl_export($crl_res, $crl_text, $ca_str_key);
475
	$crl['text'] = base64_encode($crl_text);
476
	return $crl_res;
477
}
478

    
479
function cert_revoke($cert, & $crl, $reason=OCSP_REVOKED_STATUS_UNSPECIFIED) {
480
	global $config;
481
	if (is_cert_revoked($cert))
482
		return true;
483
	$cert["reason"] = $reason;
484
	$cert["revoke_time"] = time();
485
	$crl["cert"][] = $cert;
486
	crl_update($crl);
487
}
488

    
489
function cert_unrevoke($cert, & $crl) {
490
	global $config;
491
	foreach ($crl['cert'] as $id => $rcert) {
492
		if (($rcert['refid'] == $cert['refid']) || ($rcert['name'] == $cert['name'])) {
493
			unset($crl['cert'][$id]);
494
			crl_update($crl);
495
			return true;
496
		}
497
	}
498
	return false;
499
}
500

    
501
function is_cert_revoked($cert) {
502
	global $config;
503
	if (!is_array($config['crl']) || is_array($config['crl']['cert']))
504
		return false;
505

    
506
	foreach ($config['crl'] as $crl) {
507
		if (!is_array($config['crl']['cert']))
508
			continue;
509
		foreach ($config['crl']['cert'] as $rcert) {
510
			if (($rcert['refid'] == $cert['refid']) || ($rcert['name'] == $cert['name']))
511
				return true;
512
		}
513
	}
514
	return false;
515
}
516

    
517
?>
(7-7/54)