Project

General

Profile

Download (22.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	certs.inc
4

    
5
	part of pfSense (https://www.pfsense.org)
6
	Copyright (c) 2008-2016 Electric Sheep Fencing, LLC. All rights reserved.
7
	Copyright (c) 2008 Shrew Soft Inc. 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
17
	   the documentation and/or other materials provided with the
18
	   distribution.
19

    
20
	3. All advertising materials mentioning features or use of this software
21
	   must display the following acknowledgment:
22
	   "This product includes software developed by the pfSense Project
23
	   for use in the pfSense® software distribution. (http://www.pfsense.org/).
24

    
25
	4. The names "pfSense" and "pfSense Project" must not be used to
26
	   endorse or promote products derived from this software without
27
	   prior written permission. For written permission, please contact
28
	   coreteam@pfsense.org.
29

    
30
	5. Products derived from this software may not be called "pfSense"
31
	   nor may "pfSense" appear in their names without prior written
32
	   permission of the Electric Sheep Fencing, LLC.
33

    
34
	6. Redistributions of any form whatsoever must retain the following
35
	   acknowledgment:
36

    
37
	"This product includes software developed by the pfSense Project
38
	for use in the pfSense software distribution (http://www.pfsense.org/).
39

    
40
	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
41
	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43
	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
44
	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45
	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47
	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49
	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51
	OF THE POSSIBILITY OF SUCH DAMAGE.
52
*/
53

    
54
define("OPEN_SSL_CONF_PATH", "/etc/ssl/openssl.cnf");
55

    
56
require_once("functions.inc");
57

    
58
global $openssl_digest_algs;
59
$openssl_digest_algs = array("sha1", "sha224", "sha256", "sha384", "sha512");
60

    
61
global $openssl_crl_status;
62
$openssl_crl_status = array(
63
	OCSP_REVOKED_STATUS_NOSTATUS              => "No Status (default)",
64
	OCSP_REVOKED_STATUS_UNSPECIFIED           => "Unspecified",
65
	OCSP_REVOKED_STATUS_KEYCOMPROMISE         => "Key Compromise",
66
	OCSP_REVOKED_STATUS_CACOMPROMISE          => "CA Compromise",
67
	OCSP_REVOKED_STATUS_AFFILIATIONCHANGED    => "Affiliation Changed",
68
	OCSP_REVOKED_STATUS_SUPERSEDED            => "Superseded",
69
	OCSP_REVOKED_STATUS_CESSATIONOFOPERATION  => "Cessation of Operation",
70
	OCSP_REVOKED_STATUS_CERTIFICATEHOLD       => "Certificate Hold"
71
);
72

    
73
function & lookup_ca($refid) {
74
	global $config;
75

    
76
	if (is_array($config['ca'])) {
77
		foreach ($config['ca'] as & $ca) {
78
			if ($ca['refid'] == $refid) {
79
				return $ca;
80
			}
81
		}
82
	}
83

    
84
	return false;
85
}
86

    
87
function & lookup_ca_by_subject($subject) {
88
	global $config;
89

    
90
	if (is_array($config['ca'])) {
91
		foreach ($config['ca'] as & $ca) {
92
			$ca_subject = cert_get_subject($ca['crt']);
93
			if ($ca_subject == $subject) {
94
				return $ca;
95
			}
96
		}
97
	}
98

    
99
	return false;
100
}
101

    
102
function & lookup_cert($refid) {
103
	global $config;
104

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

    
113
	return false;
114
}
115

    
116
function & lookup_cert_by_name($name) {
117
	global $config;
118
	if (is_array($config['cert'])) {
119
		foreach ($config['cert'] as & $cert) {
120
			if ($cert['descr'] == $name) {
121
				return $cert;
122
			}
123
		}
124
	}
125
}
126

    
127
function & lookup_crl($refid) {
128
	global $config;
129

    
130
	if (is_array($config['crl'])) {
131
		foreach ($config['crl'] as & $crl) {
132
			if ($crl['refid'] == $refid) {
133
				return $crl;
134
			}
135
		}
136
	}
137

    
138
	return false;
139
}
140

    
141
function ca_chain_array(& $cert) {
142
	if ($cert['caref']) {
143
		$chain = array();
144
		$crt = lookup_ca($cert['caref']);
145
		$chain[] = $crt;
146
		while ($crt) {
147
			$caref = $crt['caref'];
148
			if ($caref) {
149
				$crt = lookup_ca($caref);
150
			} else {
151
				$crt = false;
152
			}
153
			if ($crt) {
154
				$chain[] = $crt;
155
			}
156
		}
157
		return $chain;
158
	}
159
	return false;
160
}
161

    
162
function ca_chain(& $cert) {
163
	if ($cert['caref']) {
164
		$ca = "";
165
		$cas = ca_chain_array($cert);
166
		if (is_array($cas)) {
167
			foreach ($cas as & $ca_cert) {
168
				$ca .= base64_decode($ca_cert['crt']);
169
				$ca .= "\n";
170
			}
171
		}
172
		return $ca;
173
	}
174
	return "";
175
}
176

    
177
function ca_import(& $ca, $str, $key = "", $serial = 0) {
178
	global $config;
179

    
180
	$ca['crt'] = base64_encode($str);
181
	if (!empty($key)) {
182
		$ca['prv'] = base64_encode($key);
183
	}
184
	if (!empty($serial)) {
185
		$ca['serial'] = $serial;
186
	}
187
	$subject = cert_get_subject($str, false);
188
	$issuer = cert_get_issuer($str, false);
189

    
190
	// Find my issuer unless self-signed
191
	if ($issuer <> $subject) {
192
		$issuer_crt =& lookup_ca_by_subject($issuer);
193
		if ($issuer_crt) {
194
			$ca['caref'] = $issuer_crt['refid'];
195
		}
196
	}
197

    
198
	/* Correct if child certificate was loaded first */
199
	if (is_array($config['ca'])) {
200
		foreach ($config['ca'] as & $oca) {
201
			$issuer = cert_get_issuer($oca['crt']);
202
			if ($ca['refid'] <> $oca['refid'] && $issuer == $subject) {
203
				$oca['caref'] = $ca['refid'];
204
			}
205
		}
206
	}
207
	if (is_array($config['cert'])) {
208
		foreach ($config['cert'] as & $cert) {
209
			$issuer = cert_get_issuer($cert['crt']);
210
			if ($issuer == $subject) {
211
				$cert['caref'] = $ca['refid'];
212
			}
213
		}
214
	}
215
	return true;
216
}
217

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

    
220
	$args = array(
221
		"x509_extensions" => "v3_ca",
222
		"digest_alg" => $digest_alg,
223
		"private_key_bits" => (int)$keylen,
224
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
225
		"encrypt_key" => false);
226

    
227
	// generate a new key pair
228
	$res_key = openssl_pkey_new($args);
229
	if (!$res_key) {
230
		return false;
231
	}
232

    
233
	// generate a certificate signing request
234
	$res_csr = openssl_csr_new($dn, $res_key, $args);
235
	if (!$res_csr) {
236
		return false;
237
	}
238

    
239
	// self sign the certificate
240
	$res_crt = openssl_csr_sign($res_csr, null, $res_key, $lifetime, $args);
241
	if (!$res_crt) {
242
		return false;
243
	}
244

    
245
	// export our certificate data
246
	if (!openssl_pkey_export($res_key, $str_key) ||
247
	    !openssl_x509_export($res_crt, $str_crt)) {
248
		return false;
249
	}
250

    
251
	// return our ca information
252
	$ca['crt'] = base64_encode($str_crt);
253
	$ca['prv'] = base64_encode($str_key);
254
	$ca['serial'] = 0;
255

    
256
	return true;
257
}
258

    
259
function ca_inter_create(& $ca, $keylen, $lifetime, $dn, $caref, $digest_alg = "sha256") {
260
	// Create Intermediate Certificate Authority
261
	$signing_ca =& lookup_ca($caref);
262
	if (!$signing_ca) {
263
		return false;
264
	}
265

    
266
	$signing_ca_res_crt = openssl_x509_read(base64_decode($signing_ca['crt']));
267
	$signing_ca_res_key = openssl_pkey_get_private(array(0 => base64_decode($signing_ca['prv']) , 1 => ""));
268
	if (!$signing_ca_res_crt || !$signing_ca_res_key) {
269
		return false;
270
	}
271
	$signing_ca_serial = ++$signing_ca['serial'];
272

    
273
	$args = array(
274
		"x509_extensions" => "v3_ca",
275
		"digest_alg" => $digest_alg,
276
		"private_key_bits" => (int)$keylen,
277
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
278
		"encrypt_key" => false);
279

    
280
	// generate a new key pair
281
	$res_key = openssl_pkey_new($args);
282
	if (!$res_key) {
283
		return false;
284
	}
285

    
286
	// generate a certificate signing request
287
	$res_csr = openssl_csr_new($dn, $res_key, $args);
288
	if (!$res_csr) {
289
		return false;
290
	}
291

    
292
	// Sign the certificate
293
	$res_crt = openssl_csr_sign($res_csr, $signing_ca_res_crt, $signing_ca_res_key, $lifetime, $args, $signing_ca_serial);
294
	if (!$res_crt) {
295
		return false;
296
	}
297

    
298
	// export our certificate data
299
	if (!openssl_pkey_export($res_key, $str_key) ||
300
	    !openssl_x509_export($res_crt, $str_crt)) {
301
		return false;
302
	}
303

    
304
	// return our ca information
305
	$ca['crt'] = base64_encode($str_crt);
306
	$ca['prv'] = base64_encode($str_key);
307
	$ca['serial'] = 0;
308
	$ca['caref'] = $caref;
309

    
310
	return true;
311
}
312

    
313
function cert_import(& $cert, $crt_str, $key_str) {
314

    
315
	$cert['crt'] = base64_encode($crt_str);
316
	$cert['prv'] = base64_encode($key_str);
317

    
318
	$subject = cert_get_subject($crt_str, false);
319
	$issuer = cert_get_issuer($crt_str, false);
320

    
321
	// Find my issuer unless self-signed
322
	if ($issuer <> $subject) {
323
		$issuer_crt =& lookup_ca_by_subject($issuer);
324
		if ($issuer_crt) {
325
			$cert['caref'] = $issuer_crt['refid'];
326
		}
327
	}
328
	return true;
329
}
330

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

    
333
	$cert['type'] = $type;
334

    
335
	if ($type != "self-signed") {
336
		$cert['caref'] = $caref;
337
		$ca =& lookup_ca($caref);
338
		if (!$ca) {
339
			return false;
340
		}
341

    
342
		$ca_str_crt = base64_decode($ca['crt']);
343
		$ca_str_key = base64_decode($ca['prv']);
344
		$ca_res_crt = openssl_x509_read($ca_str_crt);
345
		$ca_res_key = openssl_pkey_get_private(array(0 => $ca_str_key, 1 => ""));
346
		if (!$ca_res_key) {
347
			return false;
348
		}
349
		$ca_serial = ++$ca['serial'];
350
	}
351

    
352
	switch ($type) {
353
		case "ca":
354
			$cert_type = "v3_ca";
355
			break;
356
		case "server":
357
		case "self-signed":
358
			$cert_type = "server";
359
			break;
360
		default:
361
			$cert_type = "usr_cert";
362
			break;
363
	}
364

    
365
	// in case of using Subject Alternative Names use other sections (with postfix '_san')
366
	// pass subjectAltName over environment variable 'SAN'
367
	if ($dn['subjectAltName']) {
368
		putenv("SAN={$dn['subjectAltName']}"); // subjectAltName can be set _only_ via configuration file
369
		$cert_type .= '_san';
370
		unset($dn['subjectAltName']);
371
	}
372

    
373
	$args = array(
374
		"x509_extensions" => $cert_type,
375
		"digest_alg" => $digest_alg,
376
		"private_key_bits" => (int)$keylen,
377
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
378
		"encrypt_key" => false);
379

    
380
	// generate a new key pair
381
	$res_key = openssl_pkey_new($args);
382
	if (!$res_key) {
383
		return false;
384
	}
385

    
386
	// If this is a self-signed cert, blank out the CA and sign with the cert's key
387
	if ($type == "self-signed") {
388
		$ca           = null;
389
		$ca_res_crt   = null;
390
		$ca_res_key   = $res_key;
391
		$ca_serial    = 0;
392
		$cert['type'] = "server";
393
	}
394

    
395
	// generate a certificate signing request
396
	$res_csr = openssl_csr_new($dn, $res_key, $args);
397
	if (!$res_csr) {
398
		return false;
399
	}
400

    
401
	// sign the certificate using an internal CA
402
	$res_crt = openssl_csr_sign($res_csr, $ca_res_crt, $ca_res_key, $lifetime,
403
				 $args, $ca_serial);
404
	if (!$res_crt) {
405
		return false;
406
	}
407

    
408
	// export our certificate data
409
	if (!openssl_pkey_export($res_key, $str_key) ||
410
	    !openssl_x509_export($res_crt, $str_crt)) {
411
		return false;
412
	}
413

    
414
	// return our certificate information
415
	$cert['crt'] = base64_encode($str_crt);
416
	$cert['prv'] = base64_encode($str_key);
417

    
418
	return true;
419
}
420

    
421
function csr_generate(& $cert, $keylen, $dn, $digest_alg = "sha256") {
422

    
423
	$args = array(
424
		"x509_extensions" => "v3_req",
425
		"digest_alg" => $digest_alg,
426
		"private_key_bits" => (int)$keylen,
427
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
428
		"encrypt_key" => false);
429

    
430
	// generate a new key pair
431
	$res_key = openssl_pkey_new($args);
432
	if (!$res_key) {
433
		return false;
434
	}
435

    
436
	// generate a certificate signing request
437
	$res_csr = openssl_csr_new($dn, $res_key, $args);
438
	if (!$res_csr) {
439
		return false;
440
	}
441

    
442
	// export our request data
443
	if (!openssl_pkey_export($res_key, $str_key) ||
444
	    !openssl_csr_export($res_csr, $str_csr)) {
445
		return false;
446
	}
447

    
448
	// return our request information
449
	$cert['csr'] = base64_encode($str_csr);
450
	$cert['prv'] = base64_encode($str_key);
451

    
452
	return true;
453
}
454

    
455
function csr_complete(& $cert, $str_crt) {
456

    
457
	// return our request information
458
	$cert['crt'] = base64_encode($str_crt);
459
	unset($cert['csr']);
460

    
461
	return true;
462
}
463

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

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

    
470
	$components = openssl_csr_get_subject($str_crt);
471

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

    
476
	ksort($components);
477
	foreach ($components as $a => $v) {
478
		if (!strlen($subject)) {
479
			$subject = "{$a}={$v}";
480
		} else {
481
			$subject = "{$a}={$v}, {$subject}";
482
		}
483
	}
484

    
485
	return $subject;
486
}
487

    
488
function cert_get_subject($str_crt, $decode = true) {
489

    
490
	if ($decode) {
491
		$str_crt = base64_decode($str_crt);
492
	}
493

    
494
	$inf_crt = openssl_x509_parse($str_crt);
495
	$components = $inf_crt['subject'];
496

    
497
	if (empty($components) || !is_array($components)) {
498
		return "unknown";
499
	}
500

    
501
	ksort($components);
502
	foreach ($components as $a => $v) {
503
		if (is_array($v)) {
504
			ksort($v);
505
			foreach ($v as $w) {
506
				$asubject = "{$a}={$w}";
507
				$subject = (strlen($subject)) ? "{$asubject}, {$subject}" : $asubject;
508
			}
509
		} else {
510
			$asubject = "{$a}={$v}";
511
			$subject = (strlen($subject)) ? "{$asubject}, {$subject}" : $asubject;
512
		}
513
	}
514

    
515
	return $subject;
516
}
517

    
518
function cert_get_subject_array($crt) {
519
	$str_crt = base64_decode($crt);
520
	$inf_crt = openssl_x509_parse($str_crt);
521
	$components = $inf_crt['subject'];
522

    
523
	if (!is_array($components)) {
524
		return;
525
	}
526

    
527
	$subject_array = array();
528

    
529
	foreach ($components as $a => $v) {
530
		$subject_array[] = array('a' => $a, 'v' => $v);
531
	}
532

    
533
	return $subject_array;
534
}
535

    
536
function cert_get_subject_hash($crt) {
537
	$str_crt = base64_decode($crt);
538
	$inf_crt = openssl_x509_parse($str_crt);
539
	return $inf_crt['subject'];
540
}
541

    
542
function cert_get_issuer($str_crt, $decode = true) {
543

    
544
	if ($decode) {
545
		$str_crt = base64_decode($str_crt);
546
	}
547

    
548
	$inf_crt = openssl_x509_parse($str_crt);
549
	$components = $inf_crt['issuer'];
550

    
551
	if (empty($components) || !is_array($components)) {
552
		return "unknown";
553
	}
554

    
555
	ksort($components);
556
	foreach ($components as $a => $v) {
557
		if (is_array($v)) {
558
			ksort($v);
559
			foreach ($v as $w) {
560
				$aissuer = "{$a}={$w}";
561
				$issuer = (strlen($issuer)) ? "{$aissuer}, {$issuer}" : $aissuer;
562
			}
563
		} else {
564
			$aissuer = "{$a}={$v}";
565
			$issuer = (strlen($issuer)) ? "{$aissuer}, {$issuer}" : $aissuer;
566
		}
567
	}
568

    
569
	return $issuer;
570
}
571

    
572
/* this function works on x509 (crt), rsa key (prv), and req(csr) */
573
function cert_get_modulus($str_crt, $decode = true, $type = "crt") {
574
	if ($decode) {
575
		$str_crt = base64_decode($str_crt);
576
	}
577

    
578
	$modulus = "";
579
	if (in_array($type, array("crt", "prv", "csr"))) {
580
		$type = str_replace(array("crt", "prv", "csr"), array("x509", "rsa", "req"), $type);
581
		$modulus = exec("echo \"{$str_crt}\" | openssl {$type} -noout -modulus");
582
	}
583
	return $modulus;
584
}
585
function csr_get_modulus($str_crt, $decode = true) {
586
	return cert_get_modulus($str_crt, $decode, "csr");
587
}
588

    
589
function cert_get_purpose($str_crt, $decode = true) {
590
	if ($decode) {
591
		$str_crt = base64_decode($str_crt);
592
	}
593
	$crt_details = openssl_x509_parse($str_crt);
594
	$purpose = array();
595
	$purpose['ca'] = (stristr($crt_details['extensions']['basicConstraints'], 'CA:TRUE') === false) ? 'No': 'Yes';
596
	$purpose['server'] = ($crt_details['extensions']['nsCertType'] == "SSL Server") ? 'Yes': 'No';
597
	return $purpose;
598
}
599

    
600
function cert_get_dates($str_crt, $decode = true) {
601
	if ($decode) {
602
		$str_crt = base64_decode($str_crt);
603
	}
604
	$crt_details = openssl_x509_parse($str_crt);
605
	if ($crt_details['validFrom_time_t'] > 0) {
606
		$start = date('r', $crt_details['validFrom_time_t']);
607
	}
608
	if ($crt_details['validTo_time_t'] > 0) {
609
		$end = date('r', $crt_details['validTo_time_t']);
610
	}
611
	return array($start, $end);
612
}
613

    
614
function cert_get_serial($str_crt, $decode = true) {
615
	if ($decode) {
616
		$str_crt = base64_decode($str_crt);
617
	}
618
	$crt_details = openssl_x509_parse($str_crt);
619
	if (isset($crt_details['serialNumber']) && !empty($crt_details['serialNumber'])) {
620
		return $crt_details['serialNumber'];
621
	} else {
622
		return NULL;
623
	}
624
}
625

    
626
function prv_get_modulus($str_crt, $decode = true) {
627
	return cert_get_modulus($str_crt, $decode, "prv");
628
}
629

    
630
function is_user_cert($certref) {
631
	global $config;
632
	if (!is_array($config['system']['user'])) {
633
		return;
634
	}
635
	foreach ($config['system']['user'] as $user) {
636
		if (!is_array($user['cert'])) {
637
			continue;
638
		}
639
		foreach ($user['cert'] as $cert) {
640
			if ($certref == $cert) {
641
				return true;
642
			}
643
		}
644
	}
645
	return false;
646
}
647

    
648
function is_openvpn_server_cert($certref) {
649
	global $config;
650
	if (!is_array($config['openvpn']['openvpn-server'])) {
651
		return;
652
	}
653
	foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
654
		if ($ovpns['certref'] == $certref) {
655
			return true;
656
		}
657
	}
658
	return false;
659
}
660

    
661
function is_openvpn_client_cert($certref) {
662
	global $config;
663
	if (!is_array($config['openvpn']['openvpn-client'])) {
664
		return;
665
	}
666
	foreach ($config['openvpn']['openvpn-client'] as $ovpnc) {
667
		if ($ovpnc['certref'] == $certref) {
668
			return true;
669
		}
670
	}
671
	return false;
672
}
673

    
674
function is_ipsec_cert($certref) {
675
	global $config;
676
	if (!is_array($config['ipsec']['phase1'])) {
677
		return;
678
	}
679
	foreach ($config['ipsec']['phase1'] as $ipsec) {
680
		if ($ipsec['certref'] == $certref) {
681
			return true;
682
		}
683
	}
684
	return false;
685
}
686

    
687
function is_webgui_cert($certref) {
688
	global $config;
689
	if (($config['system']['webgui']['ssl-certref'] == $certref) &&
690
	    ($config['system']['webgui']['protocol'] != "http")) {
691
		return true;
692
	}
693
}
694

    
695
function is_package_cert($certref) {
696
	$pluginparams = array();
697
	$pluginparams['type'] = 'certificates';
698
	$pluginparams['event'] = 'used_certificates';
699

    
700
	$certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
701

    
702
	/* Check if any package is using certificate */
703
	foreach ($certificates_used_by_packages as $name => $package) {
704
		if (is_array($package['certificatelist'][$certref]) &&
705
		    isset($package['certificatelist'][$certref]) > 0) {
706
			return true;
707
		}
708
	}
709
}
710

    
711
function is_captiveportal_cert($certref) {
712
	global $config;
713
	if (!is_array($config['captiveportal'])) {
714
		return;
715
	}
716
	foreach ($config['captiveportal'] as $portal) {
717
		if (isset($portal['enable']) && isset($portal['httpslogin']) && ($portal['certref'] == $certref)) {
718
			return true;
719
		}
720
	}
721
	return false;
722
}
723

    
724
function cert_in_use($certref) {
725

    
726
	return (is_webgui_cert($certref) ||
727
		is_user_cert($certref) ||
728
		is_openvpn_server_cert($certref) ||
729
		is_openvpn_client_cert($certref) ||
730
		is_ipsec_cert($certref) ||
731
		is_captiveportal_cert($certref) ||
732
		is_package_cert($certref));
733
}
734

    
735
function crl_create(& $crl, $caref, $name, $serial = 0, $lifetime = 9999) {
736
	global $config;
737
	$ca =& lookup_ca($caref);
738
	if (!$ca) {
739
		return false;
740
	}
741
	$crl['descr'] = $name;
742
	$crl['caref'] = $caref;
743
	$crl['serial'] = $serial;
744
	$crl['lifetime'] = $lifetime;
745
	$crl['cert'] = array();
746
	$crl_res = crl_update($crl);
747
	$config['crl'][] = $crl;
748
	return $crl_res;
749
}
750

    
751
function crl_update(& $crl) {
752
	global $config;
753
	$ca =& lookup_ca($crl['caref']);
754
	if (!$ca) {
755
		return false;
756
	}
757
	// If we have text but no certs, it was imported and cannot be updated.
758
	if (($crl["method"] != "internal") && (!empty($crl['text']) && empty($crl['cert']))) {
759
		return false;
760
	}
761
	$crl['serial']++;
762
	$ca_str_crt = base64_decode($ca['crt']);
763
	$ca_str_key = base64_decode($ca['prv']);
764
	$crl_res = openssl_crl_new($ca_str_crt, $crl['serial'], $crl['lifetime']);
765
	if (is_array($crl['cert']) && (count($crl['cert']) > 0)) {
766
		foreach ($crl['cert'] as $cert) {
767
			openssl_crl_revoke_cert($crl_res, base64_decode($cert["crt"]), $cert["revoke_time"], $cert["reason"]);
768
		}
769
	}
770
	openssl_crl_export($crl_res, $crl_text, $ca_str_key);
771
	$crl['text'] = base64_encode($crl_text);
772
	return $crl_res;
773
}
774

    
775
function cert_revoke($cert, & $crl, $reason = OCSP_REVOKED_STATUS_UNSPECIFIED) {
776
	global $config;
777
	if (is_cert_revoked($cert, $crl['refid'])) {
778
		return true;
779
	}
780
	// If we have text but no certs, it was imported and cannot be updated.
781
	if (!is_crl_internal($crl)) {
782
		return false;
783
	}
784
	$cert["reason"] = $reason;
785
	$cert["revoke_time"] = time();
786
	$crl["cert"][] = $cert;
787
	crl_update($crl);
788
	return true;
789
}
790

    
791
function cert_unrevoke($cert, & $crl) {
792
	global $config;
793
	if (!is_crl_internal($crl)) {
794
		return false;
795
	}
796
	foreach ($crl['cert'] as $id => $rcert) {
797
		if (($rcert['refid'] == $cert['refid']) || ($rcert['descr'] == $cert['descr'])) {
798
			unset($crl['cert'][$id]);
799
			if (count($crl['cert']) == 0) {
800
				// Protect against accidentally switching the type to imported, for older CRLs
801
				if (!isset($crl['method'])) {
802
					$crl['method'] = "internal";
803
				}
804
				crl_update($crl);
805
			} else {
806
				crl_update($crl);
807
			}
808
			return true;
809
		}
810
	}
811
	return false;
812
}
813

    
814
/* Compare two certificates to see if they match. */
815
function cert_compare($cert1, $cert2) {
816
	/* Ensure two certs are identical by first checking that their issuers match, then
817
		subjects, then serial numbers, and finally the moduli. Anything less strict
818
		could accidentally count two similar, but different, certificates as
819
		being identical. */
820
	$c1 = base64_decode($cert1['crt']);
821
	$c2 = base64_decode($cert2['crt']);
822
	if ((cert_get_issuer($c1, false) == cert_get_issuer($c2, false)) &&
823
	    (cert_get_subject($c1, false) == cert_get_subject($c2, false)) &&
824
	    (cert_get_serial($c1, false) == cert_get_serial($c2, false)) &&
825
	    (cert_get_modulus($c1, false) == cert_get_modulus($c2, false))) {
826
		return true;
827
	}
828
	return false;
829
}
830

    
831
function is_cert_revoked($cert, $crlref = "") {
832
	global $config;
833
	if (!is_array($config['crl'])) {
834
		return false;
835
	}
836

    
837
	if (!empty($crlref)) {
838
		$crl = lookup_crl($crlref);
839
		if (!is_array($crl['cert'])) {
840
			return false;
841
		}
842
		foreach ($crl['cert'] as $rcert) {
843
			if (cert_compare($rcert, $cert)) {
844
				return true;
845
			}
846
		}
847
	} else {
848
		foreach ($config['crl'] as $crl) {
849
			if (!is_array($crl['cert'])) {
850
				continue;
851
			}
852
			foreach ($crl['cert'] as $rcert) {
853
				if (cert_compare($rcert, $cert)) {
854
					return true;
855
				}
856
			}
857
		}
858
	}
859
	return false;
860
}
861

    
862
function is_openvpn_server_crl($crlref) {
863
	global $config;
864
	if (!is_array($config['openvpn']['openvpn-server'])) {
865
		return;
866
	}
867
	foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
868
		if (!empty($ovpns['crlref']) && ($ovpns['crlref'] == $crlref)) {
869
			return true;
870
		}
871
	}
872
	return false;
873
}
874

    
875
// Keep this general to allow for future expansion. See cert_in_use() above.
876
function crl_in_use($crlref) {
877
	return (is_openvpn_server_crl($crlref));
878
}
879

    
880
function is_crl_internal($crl) {
881
	return (!(!empty($crl['text']) && empty($crl['cert'])) || ($crl["method"] == "internal"));
882
}
883

    
884
function cert_get_cn($crt, $isref = false) {
885
	/* If this is a certref, not an actual cert, look up the cert first */
886
	if ($isref) {
887
		$cert = lookup_cert($crt);
888
		/* If it's not a valid cert, bail. */
889
		if (!(is_array($cert) && !empty($cert['crt']))) {
890
			return "";
891
		}
892
		$cert = $cert['crt'];
893
	} else {
894
		$cert = $crt;
895
	}
896
	$sub = cert_get_subject_array($cert);
897
	if (is_array($sub)) {
898
		foreach ($sub as $s) {
899
			if (strtoupper($s['a']) == "CN") {
900
				return $s['v'];
901
			}
902
		}
903
	}
904
	return "";
905
}
906

    
907
?>
(8-8/65)