Project

General

Profile

Download (20.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	certs.inc
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

    
30
define("OPEN_SSL_CONF_PATH", "/etc/ssl/openssl.cnf");
31

    
32
require_once("functions.inc");
33

    
34
global $openssl_digest_algs;
35
$openssl_digest_algs = array("sha1", "sha224", "sha256", "sha384", "sha512");
36

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

    
49
function & lookup_ca($refid) {
50
	global $config;
51

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

    
60
	return false;
61
}
62

    
63
function & lookup_ca_by_subject($subject) {
64
	global $config;
65

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

    
75
	return false;
76
}
77

    
78
function & lookup_cert($refid) {
79
	global $config;
80

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

    
89
	return false;
90
}
91

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

    
103
function & lookup_crl($refid) {
104
	global $config;
105

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

    
114
	return false;
115
}
116

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

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

    
153
function ca_import(& $ca, $str, $key = "", $serial = 0) {
154
	global $config;
155

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

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

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

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

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

    
203
	// generate a new key pair
204
	$res_key = openssl_pkey_new($args);
205
	if (!$res_key) {
206
		return false;
207
	}
208

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

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

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

    
227
	// return our ca information
228
	$ca['crt'] = base64_encode($str_crt);
229
	$ca['prv'] = base64_encode($str_key);
230
	$ca['serial'] = 0;
231

    
232
	return true;
233
}
234

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

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

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

    
256
	// generate a new key pair
257
	$res_key = openssl_pkey_new($args);
258
	if (!$res_key) {
259
		return false;
260
	}
261

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

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

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

    
280
	// return our ca information
281
	$ca['crt'] = base64_encode($str_crt);
282
	$ca['prv'] = base64_encode($str_key);
283
	$ca['serial'] = 0;
284
	$ca['caref'] = $caref;
285

    
286
	return true;
287
}
288

    
289
function cert_import(& $cert, $crt_str, $key_str) {
290

    
291
	$cert['crt'] = base64_encode($crt_str);
292
	$cert['prv'] = base64_encode($key_str);
293

    
294
	$subject = cert_get_subject($crt_str, false);
295
	$issuer = cert_get_issuer($crt_str, false);
296

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

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

    
309
	$cert['type'] = $type;
310

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

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

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

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

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

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

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

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

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

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

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

    
394
	return true;
395
}
396

    
397
function csr_generate(& $cert, $keylen, $dn, $digest_alg = "sha256") {
398

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

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

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

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

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

    
428
	return true;
429
}
430

    
431
function csr_complete(& $cert, $str_crt) {
432

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

    
437
	return true;
438
}
439

    
440
function csr_get_subject($str_crt, $decode = true) {
441

    
442
	if ($decode) {
443
		$str_crt = base64_decode($str_crt);
444
	}
445

    
446
	$components = openssl_csr_get_subject($str_crt);
447

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

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

    
461
	return $subject;
462
}
463

    
464
function cert_get_subject($str_crt, $decode = true) {
465

    
466
	if ($decode) {
467
		$str_crt = base64_decode($str_crt);
468
	}
469

    
470
	$inf_crt = openssl_x509_parse($str_crt);
471
	$components = $inf_crt['subject'];
472

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

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

    
491
	return $subject;
492
}
493

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

    
499
	if (!is_array($components)) {
500
		return;
501
	}
502

    
503
	$subject_array = array();
504

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

    
509
	return $subject_array;
510
}
511

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

    
518
function cert_get_issuer($str_crt, $decode = true) {
519

    
520
	if ($decode) {
521
		$str_crt = base64_decode($str_crt);
522
	}
523

    
524
	$inf_crt = openssl_x509_parse($str_crt);
525
	$components = $inf_crt['issuer'];
526

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

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

    
545
	return $issuer;
546
}
547

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
865
?>
(8-8/65)