Project

General

Profile

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

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

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

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

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

    
30
	pfSense_MODULE:	certificate_manager
31
*/
32

    
33
define("OPEN_SSL_CONF_PATH", "/etc/ssl/openssl.cnf");
34

    
35
require_once("functions.inc");
36

    
37
global $openssl_digest_algs;
38
$openssl_digest_algs = array("sha1", "sha224", "sha256", "sha384", "sha512");
39

    
40
global $openssl_crl_status;
41
$openssl_crl_status = array(
42
	OCSP_REVOKED_STATUS_NOSTATUS              => "No Status (default)",
43
	OCSP_REVOKED_STATUS_UNSPECIFIED           => "Unspecified",
44
	OCSP_REVOKED_STATUS_KEYCOMPROMISE         => "Key Compromise",
45
	OCSP_REVOKED_STATUS_CACOMPROMISE          => "CA Compromise",
46
	OCSP_REVOKED_STATUS_AFFILIATIONCHANGED    => "Affiliation Changed",
47
	OCSP_REVOKED_STATUS_SUPERSEDED            => "Superseded",
48
	OCSP_REVOKED_STATUS_CESSATIONOFOPERATION  => "Cessation of Operation",
49
	OCSP_REVOKED_STATUS_CERTIFICATEHOLD       => "Certificate Hold"
50
);
51

    
52
function & lookup_ca($refid) {
53
	global $config;
54

    
55
	if (is_array($config['ca'])) {
56
		foreach ($config['ca'] as & $ca) {
57
			if ($ca['refid'] == $refid) {
58
				return $ca;
59
			}
60
		}
61
	}
62

    
63
	return false;
64
}
65

    
66
function & lookup_ca_by_subject($subject) {
67
	global $config;
68

    
69
	if (is_array($config['ca'])) {
70
		foreach ($config['ca'] as & $ca) {
71
			$ca_subject = cert_get_subject($ca['crt']);
72
			if ($ca_subject == $subject) {
73
				return $ca;
74
			}
75
		}
76
	}
77

    
78
	return false;
79
}
80

    
81
function & lookup_cert($refid) {
82
	global $config;
83

    
84
	if (is_array($config['cert'])) {
85
		foreach ($config['cert'] as & $cert) {
86
			if ($cert['refid'] == $refid) {
87
				return $cert;
88
			}
89
		}
90
	}
91

    
92
	return false;
93
}
94

    
95
function & lookup_cert_by_name($name) {
96
	global $config;
97
	if (is_array($config['cert'])) {
98
		foreach ($config['cert'] as & $cert) {
99
			if ($cert['descr'] == $name) {
100
				return $cert;
101
			}
102
		}
103
	}
104
}
105

    
106
function & lookup_crl($refid) {
107
	global $config;
108

    
109
	if (is_array($config['crl'])) {
110
		foreach ($config['crl'] as & $crl) {
111
			if ($crl['refid'] == $refid) {
112
				return $crl;
113
			}
114
		}
115
	}
116

    
117
	return false;
118
}
119

    
120
function ca_chain_array(& $cert) {
121
	if ($cert['caref']) {
122
		$chain = array();
123
		$crt = lookup_ca($cert['caref']);
124
		$chain[] = $crt;
125
		while ($crt) {
126
			$caref = $crt['caref'];
127
			if ($caref) {
128
				$crt = lookup_ca($caref);
129
			} else {
130
				$crt = false;
131
			}
132
			if ($crt) {
133
				$chain[] = $crt;
134
			}
135
		}
136
		return $chain;
137
	}
138
	return false;
139
}
140

    
141
function ca_chain(& $cert) {
142
	if ($cert['caref']) {
143
		$ca = "";
144
		$cas = ca_chain_array($cert);
145
		if (is_array($cas)) {
146
			foreach ($cas as & $ca_cert) {
147
				$ca .= base64_decode($ca_cert['crt']);
148
				$ca .= "\n";
149
			}
150
		}
151
		return $ca;
152
	}
153
	return "";
154
}
155

    
156
function ca_import(& $ca, $str, $key = "", $serial = 0) {
157
	global $config;
158

    
159
	$ca['crt'] = base64_encode($str);
160
	if (!empty($key)) {
161
		$ca['prv'] = base64_encode($key);
162
	}
163
	if (!empty($serial)) {
164
		$ca['serial'] = $serial;
165
	}
166
	$subject = cert_get_subject($str, false);
167
	$issuer = cert_get_issuer($str, false);
168

    
169
	// Find my issuer unless self-signed
170
	if ($issuer <> $subject) {
171
		$issuer_crt =& lookup_ca_by_subject($issuer);
172
		if ($issuer_crt) {
173
			$ca['caref'] = $issuer_crt['refid'];
174
		}
175
	}
176

    
177
	/* Correct if child certificate was loaded first */
178
	if (is_array($config['ca'])) {
179
		foreach ($config['ca'] as & $oca) {
180
			$issuer = cert_get_issuer($oca['crt']);
181
			if ($ca['refid'] <> $oca['refid'] && $issuer == $subject) {
182
				$oca['caref'] = $ca['refid'];
183
			}
184
		}
185
	}
186
	if (is_array($config['cert'])) {
187
		foreach ($config['cert'] as & $cert) {
188
			$issuer = cert_get_issuer($cert['crt']);
189
			if ($issuer == $subject) {
190
				$cert['caref'] = $ca['refid'];
191
			}
192
		}
193
	}
194
	return true;
195
}
196

    
197
function ca_create(& $ca, $keylen, $lifetime, $dn, $digest_alg = "sha256") {
198

    
199
	$args = array(
200
		"x509_extensions" => "v3_ca",
201
		"digest_alg" => $digest_alg,
202
		"private_key_bits" => (int)$keylen,
203
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
204
		"encrypt_key" => false);
205

    
206
	// generate a new key pair
207
	$res_key = openssl_pkey_new($args);
208
	if (!$res_key) {
209
		return false;
210
	}
211

    
212
	// generate a certificate signing request
213
	$res_csr = openssl_csr_new($dn, $res_key, $args);
214
	if (!$res_csr) {
215
		return false;
216
	}
217

    
218
	// self sign the certificate
219
	$res_crt = openssl_csr_sign($res_csr, null, $res_key, $lifetime, $args);
220
	if (!$res_crt) {
221
		return false;
222
	}
223

    
224
	// export our certificate data
225
	if (!openssl_pkey_export($res_key, $str_key) ||
226
	    !openssl_x509_export($res_crt, $str_crt)) {
227
		return false;
228
	}
229

    
230
	// return our ca information
231
	$ca['crt'] = base64_encode($str_crt);
232
	$ca['prv'] = base64_encode($str_key);
233
	$ca['serial'] = 0;
234

    
235
	return true;
236
}
237

    
238
function ca_inter_create(& $ca, $keylen, $lifetime, $dn, $caref, $digest_alg = "sha256") {
239
	// Create Intermediate Certificate Authority
240
	$signing_ca =& lookup_ca($caref);
241
	if (!$signing_ca) {
242
		return false;
243
	}
244

    
245
	$signing_ca_res_crt = openssl_x509_read(base64_decode($signing_ca['crt']));
246
	$signing_ca_res_key = openssl_pkey_get_private(array(0 => base64_decode($signing_ca['prv']) , 1 => ""));
247
	if (!$signing_ca_res_crt || !$signing_ca_res_key) {
248
		return false;
249
	}
250
	$signing_ca_serial = ++$signing_ca['serial'];
251

    
252
	$args = array(
253
		"x509_extensions" => "v3_ca",
254
		"digest_alg" => $digest_alg,
255
		"private_key_bits" => (int)$keylen,
256
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
257
		"encrypt_key" => false);
258

    
259
	// generate a new key pair
260
	$res_key = openssl_pkey_new($args);
261
	if (!$res_key) {
262
		return false;
263
	}
264

    
265
	// generate a certificate signing request
266
	$res_csr = openssl_csr_new($dn, $res_key, $args);
267
	if (!$res_csr) {
268
		return false;
269
	}
270

    
271
	// Sign the certificate
272
	$res_crt = openssl_csr_sign($res_csr, $signing_ca_res_crt, $signing_ca_res_key, $lifetime, $args, $signing_ca_serial);
273
	if (!$res_crt) {
274
		return false;
275
	}
276

    
277
	// export our certificate data
278
	if (!openssl_pkey_export($res_key, $str_key) ||
279
	    !openssl_x509_export($res_crt, $str_crt)) {
280
		return false;
281
	}
282

    
283
	// return our ca information
284
	$ca['crt'] = base64_encode($str_crt);
285
	$ca['prv'] = base64_encode($str_key);
286
	$ca['serial'] = 0;
287

    
288
	return true;
289
}
290

    
291
function cert_import(& $cert, $crt_str, $key_str) {
292

    
293
	$cert['crt'] = base64_encode($crt_str);
294
	$cert['prv'] = base64_encode($key_str);
295

    
296
	$subject = cert_get_subject($crt_str, false);
297
	$issuer = cert_get_issuer($crt_str, false);
298

    
299
	// Find my issuer unless self-signed
300
	if ($issuer <> $subject) {
301
		$issuer_crt =& lookup_ca_by_subject($issuer);
302
		if ($issuer_crt) {
303
			$cert['caref'] = $issuer_crt['refid'];
304
		}
305
	}
306
	return true;
307
}
308

    
309
function cert_create(& $cert, $caref, $keylen, $lifetime, $dn, $type = "user", $digest_alg = "sha256") {
310

    
311
	$cert['type'] = $type;
312

    
313
	if ($type != "self-signed") {
314
		$cert['caref'] = $caref;
315
		$ca =& lookup_ca($caref);
316
		if (!$ca) {
317
			return false;
318
		}
319

    
320
		$ca_str_crt = base64_decode($ca['crt']);
321
		$ca_str_key = base64_decode($ca['prv']);
322
		$ca_res_crt = openssl_x509_read($ca_str_crt);
323
		$ca_res_key = openssl_pkey_get_private(array(0 => $ca_str_key, 1 => ""));
324
		if (!$ca_res_key) {
325
			return false;
326
		}
327
		$ca_serial = ++$ca['serial'];
328
	}
329

    
330
	switch ($type) {
331
		case "ca":
332
			$cert_type = "v3_ca";
333
			break;
334
		case "server":
335
		case "self-signed":
336
			$cert_type = "server";
337
			break;
338
		default:
339
			$cert_type = "usr_cert";
340
			break;
341
	}
342

    
343
	// in case of using Subject Alternative Names use other sections (with postfix '_san')
344
	// pass subjectAltName over environment variable 'SAN'
345
	if ($dn['subjectAltName']) {
346
		putenv("SAN={$dn['subjectAltName']}"); // subjectAltName can be set _only_ via configuration file
347
		$cert_type .= '_san';
348
		unset($dn['subjectAltName']);
349
	}
350

    
351
	$args = array(
352
		"x509_extensions" => $cert_type,
353
		"digest_alg" => $digest_alg,
354
		"private_key_bits" => (int)$keylen,
355
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
356
		"encrypt_key" => false);
357

    
358
	// generate a new key pair
359
	$res_key = openssl_pkey_new($args);
360
	if (!$res_key) {
361
		return false;
362
	}
363

    
364
	// If this is a self-signed cert, blank out the CA and sign with the cert's key
365
	if ($type == "self-signed") {
366
		$ca           = null;
367
		$ca_res_crt   = null;
368
		$ca_res_key   = $res_key;
369
		$ca_serial    = 0;
370
		$cert['type'] = "server";
371
	}
372

    
373
	// generate a certificate signing request
374
	$res_csr = openssl_csr_new($dn, $res_key, $args);
375
	if (!$res_csr) {
376
		return false;
377
	}
378

    
379
	// sign the certificate using an internal CA
380
	$res_crt = openssl_csr_sign($res_csr, $ca_res_crt, $ca_res_key, $lifetime,
381
				 $args, $ca_serial);
382
	if (!$res_crt) {
383
		return false;
384
	}
385

    
386
	// export our certificate data
387
	if (!openssl_pkey_export($res_key, $str_key) ||
388
	    !openssl_x509_export($res_crt, $str_crt)) {
389
		return false;
390
	}
391

    
392
	// return our certificate information
393
	$cert['crt'] = base64_encode($str_crt);
394
	$cert['prv'] = base64_encode($str_key);
395

    
396
	return true;
397
}
398

    
399
function csr_generate(& $cert, $keylen, $dn, $digest_alg = "sha256") {
400

    
401
	$args = array(
402
		"x509_extensions" => "v3_req",
403
		"digest_alg" => $digest_alg,
404
		"private_key_bits" => (int)$keylen,
405
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
406
		"encrypt_key" => false);
407

    
408
	// generate a new key pair
409
	$res_key = openssl_pkey_new($args);
410
	if (!$res_key) {
411
		return false;
412
	}
413

    
414
	// generate a certificate signing request
415
	$res_csr = openssl_csr_new($dn, $res_key, $args);
416
	if (!$res_csr) {
417
		return false;
418
	}
419

    
420
	// export our request data
421
	if (!openssl_pkey_export($res_key, $str_key) ||
422
	    !openssl_csr_export($res_csr, $str_csr)) {
423
		return false;
424
	}
425

    
426
	// return our request information
427
	$cert['csr'] = base64_encode($str_csr);
428
	$cert['prv'] = base64_encode($str_key);
429

    
430
	return true;
431
}
432

    
433
function csr_complete(& $cert, $str_crt) {
434

    
435
	// return our request information
436
	$cert['crt'] = base64_encode($str_crt);
437
	unset($cert['csr']);
438

    
439
	return true;
440
}
441

    
442
function csr_get_subject($str_crt, $decode = true) {
443

    
444
	if ($decode) {
445
		$str_crt = base64_decode($str_crt);
446
	}
447

    
448
	$components = openssl_csr_get_subject($str_crt);
449

    
450
	if (empty($components) || !is_array($components)) {
451
		return "unknown";
452
	}
453

    
454
	ksort($components);
455
	foreach ($components as $a => $v) {
456
		if (!strlen($subject)) {
457
			$subject = "{$a}={$v}";
458
		} else {
459
			$subject = "{$a}={$v}, {$subject}";
460
		}
461
	}
462

    
463
	return $subject;
464
}
465

    
466
function cert_get_subject($str_crt, $decode = true) {
467

    
468
	if ($decode) {
469
		$str_crt = base64_decode($str_crt);
470
	}
471

    
472
	$inf_crt = openssl_x509_parse($str_crt);
473
	$components = $inf_crt['subject'];
474

    
475
	if (empty($components) || !is_array($components)) {
476
		return "unknown";
477
	}
478

    
479
	ksort($components);
480
	foreach ($components as $a => $v) {
481
		if (is_array($v)) {
482
			ksort($v);
483
			foreach ($v as $w) {
484
				$asubject = "{$a}={$w}";
485
				$subject = (strlen($subject)) ? "{$asubject}, {$subject}" : $asubject;
486
			}
487
		} else {
488
			$asubject = "{$a}={$v}";
489
			$subject = (strlen($subject)) ? "{$asubject}, {$subject}" : $asubject;
490
		}
491
	}
492

    
493
	return $subject;
494
}
495

    
496
function cert_get_subject_array($crt) {
497
	$str_crt = base64_decode($crt);
498
	$inf_crt = openssl_x509_parse($str_crt);
499
	$components = $inf_crt['subject'];
500

    
501
	if (!is_array($components)) {
502
		return;
503
	}
504

    
505
	$subject_array = array();
506

    
507
	foreach ($components as $a => $v) {
508
		$subject_array[] = array('a' => $a, 'v' => $v);
509
	}
510

    
511
	return $subject_array;
512
}
513

    
514
function cert_get_subject_hash($crt) {
515
	$str_crt = base64_decode($crt);
516
	$inf_crt = openssl_x509_parse($str_crt);
517
	return $inf_crt['subject'];
518
}
519

    
520
function cert_get_issuer($str_crt, $decode = true) {
521

    
522
	if ($decode) {
523
		$str_crt = base64_decode($str_crt);
524
	}
525

    
526
	$inf_crt = openssl_x509_parse($str_crt);
527
	$components = $inf_crt['issuer'];
528

    
529
	if (empty($components) || !is_array($components)) {
530
		return "unknown";
531
	}
532

    
533
	ksort($components);
534
	foreach ($components as $a => $v) {
535
		if (is_array($v)) {
536
			ksort($v);
537
			foreach ($v as $w) {
538
				$aissuer = "{$a}={$w}";
539
				$issuer = (strlen($issuer)) ? "{$aissuer}, {$issuer}" : $aissuer;
540
			}
541
		} else {
542
			$aissuer = "{$a}={$v}";
543
			$issuer = (strlen($issuer)) ? "{$aissuer}, {$issuer}" : $aissuer;
544
		}
545
	}
546

    
547
	return $issuer;
548
}
549

    
550
/* this function works on x509 (crt), rsa key (prv), and req(csr) */
551
function cert_get_modulus($str_crt, $decode = true, $type = "crt") {
552
	if ($decode) {
553
		$str_crt = base64_decode($str_crt);
554
	}
555

    
556
	$modulus = "";
557
	if (in_array($type, array("crt", "prv", "csr"))) {
558
		$type = str_replace(array("crt", "prv", "csr"), array("x509", "rsa", "req"), $type);
559
		$modulus = exec("echo \"{$str_crt}\" | openssl {$type} -noout -modulus");
560
	}
561
	return $modulus;
562
}
563
function csr_get_modulus($str_crt, $decode = true) {
564
	return cert_get_modulus($str_crt, $decode, "csr");
565
}
566

    
567
function cert_get_purpose($str_crt, $decode = true) {
568
	if ($decode) {
569
		$str_crt = base64_decode($str_crt);
570
	}
571
	$crt_details = openssl_x509_parse($str_crt);
572
	$purpose = array();
573
	$purpose['ca'] = (stristr($crt_details['extensions']['basicConstraints'], 'CA:TRUE') === false) ? 'No': 'Yes';
574
	$purpose['server'] = ($crt_details['extensions']['nsCertType'] == "SSL Server") ? 'Yes': 'No';
575
	return $purpose;
576
}
577

    
578
function cert_get_dates($str_crt, $decode = true) {
579
	if ($decode) {
580
		$str_crt = base64_decode($str_crt);
581
	}
582
	$crt_details = openssl_x509_parse($str_crt);
583
	if ($crt_details['validFrom_time_t'] > 0) {
584
		$start = date('r', $crt_details['validFrom_time_t']);
585
	}
586
	if ($crt_details['validTo_time_t'] > 0) {
587
		$end = date('r', $crt_details['validTo_time_t']);
588
	}
589
	return array($start, $end);
590
}
591

    
592
function cert_get_serial($str_crt, $decode = true) {
593
	if ($decode) {
594
		$str_crt = base64_decode($str_crt);
595
	}
596
	$crt_details = openssl_x509_parse($str_crt);
597
	if (isset($crt_details['serialNumber']) && !empty($crt_details['serialNumber'])) {
598
		return $crt_details['serialNumber'];
599
	} else {
600
		return NULL;
601
	}
602
}
603

    
604
function prv_get_modulus($str_crt, $decode = true) {
605
	return cert_get_modulus($str_crt, $decode, "prv");
606
}
607

    
608
function is_user_cert($certref) {
609
	global $config;
610
	if (!is_array($config['system']['user'])) {
611
		return;
612
	}
613
	foreach ($config['system']['user'] as $user) {
614
		if (!is_array($user['cert'])) {
615
			continue;
616
		}
617
		foreach ($user['cert'] as $cert) {
618
			if ($certref == $cert) {
619
				return true;
620
			}
621
		}
622
	}
623
	return false;
624
}
625

    
626
function is_openvpn_server_cert($certref) {
627
	global $config;
628
	if (!is_array($config['openvpn']['openvpn-server'])) {
629
		return;
630
	}
631
	foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
632
		if ($ovpns['certref'] == $certref) {
633
			return true;
634
		}
635
	}
636
	return false;
637
}
638

    
639
function is_openvpn_client_cert($certref) {
640
	global $config;
641
	if (!is_array($config['openvpn']['openvpn-client'])) {
642
		return;
643
	}
644
	foreach ($config['openvpn']['openvpn-client'] as $ovpnc) {
645
		if ($ovpnc['certref'] == $certref) {
646
			return true;
647
		}
648
	}
649
	return false;
650
}
651

    
652
function is_ipsec_cert($certref) {
653
	global $config;
654
	if (!is_array($config['ipsec']['phase1'])) {
655
		return;
656
	}
657
	foreach ($config['ipsec']['phase1'] as $ipsec) {
658
		if ($ipsec['certref'] == $certref) {
659
			return true;
660
		}
661
	}
662
	return false;
663
}
664

    
665
function is_webgui_cert($certref) {
666
	global $config;
667
	if (($config['system']['webgui']['ssl-certref'] == $certref) &&
668
	    ($config['system']['webgui']['protocol'] != "http")) {
669
		return true;
670
	}
671
}
672

    
673
function is_captiveportal_cert($certref) {
674
	global $config;
675
	if (!is_array($config['captiveportal'])) {
676
		return;
677
	}
678
	foreach ($config['captiveportal'] as $portal) {
679
		if (isset($portal['enable']) && isset($portal['httpslogin']) && ($portal['certref'] == $certref)) {
680
			return true;
681
		}
682
	}
683
	return false;
684
}
685

    
686
function cert_in_use($certref) {
687
	return (is_webgui_cert($certref) ||
688
		is_user_cert($certref) ||
689
		is_openvpn_server_cert($certref) ||
690
		is_openvpn_client_cert($certref) ||
691
		is_ipsec_cert($certref) ||
692
		is_captiveportal_cert($certref));
693
}
694

    
695
function crl_create(& $crl, $caref, $name, $serial = 0, $lifetime = 9999) {
696
	global $config;
697
	$ca =& lookup_ca($caref);
698
	if (!$ca) {
699
		return false;
700
	}
701
	$crl['descr'] = $name;
702
	$crl['caref'] = $caref;
703
	$crl['serial'] = $serial;
704
	$crl['lifetime'] = $lifetime;
705
	$crl['cert'] = array();
706
	$crl_res = crl_update($crl);
707
	$config['crl'][] = $crl;
708
	return $crl_res;
709
}
710

    
711
function crl_update(& $crl) {
712
	global $config;
713
	$ca =& lookup_ca($crl['caref']);
714
	if (!$ca) {
715
		return false;
716
	}
717
	// If we have text but no certs, it was imported and cannot be updated.
718
	if (($crl["method"] != "internal") && (!empty($crl['text']) && empty($crl['cert']))) {
719
		return false;
720
	}
721
	$crl['serial']++;
722
	$ca_str_crt = base64_decode($ca['crt']);
723
	$ca_str_key = base64_decode($ca['prv']);
724
	$crl_res = openssl_crl_new($ca_str_crt, $crl['serial'], $crl['lifetime']);
725
	if (is_array($crl['cert']) && (count($crl['cert']) > 0)) {
726
		foreach ($crl['cert'] as $cert) {
727
			openssl_crl_revoke_cert($crl_res, base64_decode($cert["crt"]), $cert["revoke_time"], $cert["reason"]);
728
		}
729
	}
730
	openssl_crl_export($crl_res, $crl_text, $ca_str_key);
731
	$crl['text'] = base64_encode($crl_text);
732
	return $crl_res;
733
}
734

    
735
function cert_revoke($cert, & $crl, $reason = OCSP_REVOKED_STATUS_UNSPECIFIED) {
736
	global $config;
737
	if (is_cert_revoked($cert, $crl['refid'])) {
738
		return true;
739
	}
740
	// If we have text but no certs, it was imported and cannot be updated.
741
	if (!is_crl_internal($crl)) {
742
		return false;
743
	}
744
	$cert["reason"] = $reason;
745
	$cert["revoke_time"] = time();
746
	$crl["cert"][] = $cert;
747
	crl_update($crl);
748
	return true;
749
}
750

    
751
function cert_unrevoke($cert, & $crl) {
752
	global $config;
753
	if (!is_crl_internal($crl)) {
754
		return false;
755
	}
756
	foreach ($crl['cert'] as $id => $rcert) {
757
		if (($rcert['refid'] == $cert['refid']) || ($rcert['descr'] == $cert['descr'])) {
758
			unset($crl['cert'][$id]);
759
			if (count($crl['cert']) == 0) {
760
				// Protect against accidentally switching the type to imported, for older CRLs
761
				if (!isset($crl['method'])) {
762
					$crl['method'] = "internal";
763
				}
764
				crl_update($crl);
765
			} else {
766
				crl_update($crl);
767
			}
768
			return true;
769
		}
770
	}
771
	return false;
772
}
773

    
774
/* Compare two certificates to see if they match. */
775
function cert_compare($cert1, $cert2) {
776
	/* Ensure two certs are identical by first checking that their issuers match, then
777
		subjects, then serial numbers, and finally the moduli. Anything less strict
778
		could accidentally count two similar, but different, certificates as
779
		being identical. */
780
	$c1 = base64_decode($cert1['crt']);
781
	$c2 = base64_decode($cert2['crt']);
782
	if ((cert_get_issuer($c1, false) == cert_get_issuer($c2, false)) &&
783
	    (cert_get_subject($c1, false) == cert_get_subject($c2, false)) &&
784
	    (cert_get_serial($c1, false) == cert_get_serial($c2, false)) &&
785
	    (cert_get_modulus($c1, false) == cert_get_modulus($c2, false))) {
786
		return true;
787
	}
788
	return false;
789
}
790

    
791
function is_cert_revoked($cert, $crlref = "") {
792
	global $config;
793
	if (!is_array($config['crl'])) {
794
		return false;
795
	}
796

    
797
	if (!empty($crlref)) {
798
		$crl = lookup_crl($crlref);
799
		if (!is_array($crl['cert'])) {
800
			return false;
801
		}
802
		foreach ($crl['cert'] as $rcert) {
803
			if (cert_compare($rcert, $cert)) {
804
				return true;
805
			}
806
		}
807
	} else {
808
		foreach ($config['crl'] as $crl) {
809
			if (!is_array($crl['cert'])) {
810
				continue;
811
			}
812
			foreach ($crl['cert'] as $rcert) {
813
				if (cert_compare($rcert, $cert)) {
814
					return true;
815
				}
816
			}
817
		}
818
	}
819
	return false;
820
}
821

    
822
function is_openvpn_server_crl($crlref) {
823
	global $config;
824
	if (!is_array($config['openvpn']['openvpn-server'])) {
825
		return;
826
	}
827
	foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
828
		if (!empty($ovpns['crlref']) && ($ovpns['crlref'] == $crlref)) {
829
			return true;
830
		}
831
	}
832
	return false;
833
}
834

    
835
// Keep this general to allow for future expansion. See cert_in_use() above.
836
function crl_in_use($crlref) {
837
	return (is_openvpn_server_crl($crlref));
838
}
839

    
840
function is_crl_internal($crl) {
841
	return (!(!empty($crl['text']) && empty($crl['cert'])) || ($crl["method"] == "internal"));
842
}
843

    
844
function cert_get_cn($crt, $isref = false) {
845
	/* If this is a certref, not an actual cert, look up the cert first */
846
	if ($isref) {
847
		$cert = lookup_cert($crt);
848
		/* If it's not a valid cert, bail. */
849
		if (!(is_array($cert) && !empty($cert['crt']))) {
850
			return "";
851
		}
852
		$cert = $cert['crt'];
853
	} else {
854
		$cert = $crt;
855
	}
856
	$sub = cert_get_subject_array($cert);
857
	if (is_array($sub)) {
858
		foreach ($sub as $s) {
859
			if (strtoupper($s['a']) == "CN") {
860
				return $s['v'];
861
			}
862
		}
863
	}
864
	return "";
865
}
866

    
867
?>
(8-8/68)