Project

General

Profile

Download (22.5 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
7
 * Copyright (c) 2008 Shrew Soft Inc. All rights reserved.
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions are met:
12
 *
13
 * 1. Redistributions of source code must retain the above copyright notice,
14
 *    this list of conditions and the following disclaimer.
15
 *
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in
18
 *    the documentation and/or other materials provided with the
19
 *    distribution.
20
 *
21
 * 3. All advertising materials mentioning features or use of this software
22
 *    must display the following acknowledgment:
23
 *    "This product includes software developed by the pfSense Project
24
 *    for use in the pfSense® software distribution. (http://www.pfsense.org/).
25
 *
26
 * 4. The names "pfSense" and "pfSense Project" must not be used to
27
 *    endorse or promote products derived from this software without
28
 *    prior written permission. For written permission, please contact
29
 *    coreteam@pfsense.org.
30
 *
31
 * 5. Products derived from this software may not be called "pfSense"
32
 *    nor may "pfSense" appear in their names without prior written
33
 *    permission of the Electric Sheep Fencing, LLC.
34
 *
35
 * 6. Redistributions of any form whatsoever must retain the following
36
 *    acknowledgment:
37
 *
38
 * "This product includes software developed by the pfSense Project
39
 * for use in the pfSense software distribution (http://www.pfsense.org/).
40
 *
41
 * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
42
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
44
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
45
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
48
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
50
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
52
 * OF THE POSSIBILITY OF SUCH DAMAGE.
53
 */
54

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

    
57
require_once("functions.inc");
58

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

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

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

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

    
85
	return false;
86
}
87

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

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

    
100
	return false;
101
}
102

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

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

    
114
	return false;
115
}
116

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

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

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

    
139
	return false;
140
}
141

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

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

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

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

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

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

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

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

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

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

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

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

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

    
257
	return true;
258
}
259

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

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

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

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

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

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

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

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

    
311
	return true;
312
}
313

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
419
	return true;
420
}
421

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

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

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

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

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

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

    
453
	return true;
454
}
455

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

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

    
462
	return true;
463
}
464

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

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

    
471
	$components = openssl_csr_get_subject($str_crt);
472

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

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

    
486
	return $subject;
487
}
488

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

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

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

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

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

    
516
	return $subject;
517
}
518

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

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

    
528
	$subject_array = array();
529

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

    
534
	return $subject_array;
535
}
536

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

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

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

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

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

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

    
570
	return $issuer;
571
}
572

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

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

    
587
/* Same but returns modulus keysize not modulus itself */
588
function cert_get_modulus_keysize($str_crt, $decode = true, $type = "crt") {
589
	// modulus usually returned as "modulus=.....". Remove anything before an "=" and return 4 x (hex string length)
590
	$raw_modulus = explode('=', cert_get_modulus($str_crt, $decode, $type));
591
	return strlen(array_pop($raw_modulus))*4;
592
}
593

    
594
function csr_get_modulus($str_crt, $decode = true) {
595
	return cert_get_modulus($str_crt, $decode, "csr");
596
}
597

    
598
function cert_get_purpose($str_crt, $decode = true) {
599
	if ($decode) {
600
		$str_crt = base64_decode($str_crt);
601
	}
602
	$crt_details = openssl_x509_parse($str_crt);
603
	$purpose = array();
604
	$purpose['ca'] = (stristr($crt_details['extensions']['basicConstraints'], 'CA:TRUE') === false) ? 'No': 'Yes';
605
	$purpose['server'] = ($crt_details['extensions']['nsCertType'] == "SSL Server") ? 'Yes': 'No';
606
	return $purpose;
607
}
608

    
609
function cert_get_dates($str_crt, $decode = true) {
610
	if ($decode) {
611
		$str_crt = base64_decode($str_crt);
612
	}
613
	$crt_details = openssl_x509_parse($str_crt);
614
	if ($crt_details['validFrom_time_t'] > 0) {
615
		$start = date('r', $crt_details['validFrom_time_t']);
616
	}
617
	if ($crt_details['validTo_time_t'] > 0) {
618
		$end = date('r', $crt_details['validTo_time_t']);
619
	}
620
	return array($start, $end);
621
}
622

    
623
function cert_get_serial($str_crt, $decode = true) {
624
	if ($decode) {
625
		$str_crt = base64_decode($str_crt);
626
	}
627
	$crt_details = openssl_x509_parse($str_crt);
628
	if (isset($crt_details['serialNumber']) && !empty($crt_details['serialNumber'])) {
629
		return $crt_details['serialNumber'];
630
	} else {
631
		return NULL;
632
	}
633
}
634

    
635
function prv_get_modulus($str_crt, $decode = true) {
636
	return cert_get_modulus($str_crt, $decode, "prv");
637
}
638

    
639
function is_user_cert($certref) {
640
	global $config;
641
	if (!is_array($config['system']['user'])) {
642
		return;
643
	}
644
	foreach ($config['system']['user'] as $user) {
645
		if (!is_array($user['cert'])) {
646
			continue;
647
		}
648
		foreach ($user['cert'] as $cert) {
649
			if ($certref == $cert) {
650
				return true;
651
			}
652
		}
653
	}
654
	return false;
655
}
656

    
657
function is_openvpn_server_cert($certref) {
658
	global $config;
659
	if (!is_array($config['openvpn']['openvpn-server'])) {
660
		return;
661
	}
662
	foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
663
		if ($ovpns['certref'] == $certref) {
664
			return true;
665
		}
666
	}
667
	return false;
668
}
669

    
670
function is_openvpn_client_cert($certref) {
671
	global $config;
672
	if (!is_array($config['openvpn']['openvpn-client'])) {
673
		return;
674
	}
675
	foreach ($config['openvpn']['openvpn-client'] as $ovpnc) {
676
		if ($ovpnc['certref'] == $certref) {
677
			return true;
678
		}
679
	}
680
	return false;
681
}
682

    
683
function is_ipsec_cert($certref) {
684
	global $config;
685
	if (!is_array($config['ipsec']['phase1'])) {
686
		return;
687
	}
688
	foreach ($config['ipsec']['phase1'] as $ipsec) {
689
		if ($ipsec['certref'] == $certref) {
690
			return true;
691
		}
692
	}
693
	return false;
694
}
695

    
696
function is_webgui_cert($certref) {
697
	global $config;
698
	if (($config['system']['webgui']['ssl-certref'] == $certref) &&
699
	    ($config['system']['webgui']['protocol'] != "http")) {
700
		return true;
701
	}
702
}
703

    
704
function is_package_cert($certref) {
705
	$pluginparams = array();
706
	$pluginparams['type'] = 'certificates';
707
	$pluginparams['event'] = 'used_certificates';
708

    
709
	$certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
710

    
711
	/* Check if any package is using certificate */
712
	foreach ($certificates_used_by_packages as $name => $package) {
713
		if (is_array($package['certificatelist'][$certref]) &&
714
		    isset($package['certificatelist'][$certref]) > 0) {
715
			return true;
716
		}
717
	}
718
}
719

    
720
function is_captiveportal_cert($certref) {
721
	global $config;
722
	if (!is_array($config['captiveportal'])) {
723
		return;
724
	}
725
	foreach ($config['captiveportal'] as $portal) {
726
		if (isset($portal['enable']) && isset($portal['httpslogin']) && ($portal['certref'] == $certref)) {
727
			return true;
728
		}
729
	}
730
	return false;
731
}
732

    
733
function cert_in_use($certref) {
734

    
735
	return (is_webgui_cert($certref) ||
736
		is_user_cert($certref) ||
737
		is_openvpn_server_cert($certref) ||
738
		is_openvpn_client_cert($certref) ||
739
		is_ipsec_cert($certref) ||
740
		is_captiveportal_cert($certref) ||
741
		is_package_cert($certref));
742
}
743

    
744
function crl_create(& $crl, $caref, $name, $serial = 0, $lifetime = 9999) {
745
	global $config;
746
	$ca =& lookup_ca($caref);
747
	if (!$ca) {
748
		return false;
749
	}
750
	$crl['descr'] = $name;
751
	$crl['caref'] = $caref;
752
	$crl['serial'] = $serial;
753
	$crl['lifetime'] = $lifetime;
754
	$crl['cert'] = array();
755
	$crl_res = crl_update($crl);
756
	$config['crl'][] = $crl;
757
	return $crl_res;
758
}
759

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

    
784
function cert_revoke($cert, & $crl, $reason = OCSP_REVOKED_STATUS_UNSPECIFIED) {
785
	global $config;
786
	if (is_cert_revoked($cert, $crl['refid'])) {
787
		return true;
788
	}
789
	// If we have text but no certs, it was imported and cannot be updated.
790
	if (!is_crl_internal($crl)) {
791
		return false;
792
	}
793
	$cert["reason"] = $reason;
794
	$cert["revoke_time"] = time();
795
	$crl["cert"][] = $cert;
796
	crl_update($crl);
797
	return true;
798
}
799

    
800
function cert_unrevoke($cert, & $crl) {
801
	global $config;
802
	if (!is_crl_internal($crl)) {
803
		return false;
804
	}
805
	foreach ($crl['cert'] as $id => $rcert) {
806
		if (($rcert['refid'] == $cert['refid']) || ($rcert['descr'] == $cert['descr'])) {
807
			unset($crl['cert'][$id]);
808
			if (count($crl['cert']) == 0) {
809
				// Protect against accidentally switching the type to imported, for older CRLs
810
				if (!isset($crl['method'])) {
811
					$crl['method'] = "internal";
812
				}
813
				crl_update($crl);
814
			} else {
815
				crl_update($crl);
816
			}
817
			return true;
818
		}
819
	}
820
	return false;
821
}
822

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

    
840
function is_cert_revoked($cert, $crlref = "") {
841
	global $config;
842
	if (!is_array($config['crl'])) {
843
		return false;
844
	}
845

    
846
	if (!empty($crlref)) {
847
		$crl = lookup_crl($crlref);
848
		if (!is_array($crl['cert'])) {
849
			return false;
850
		}
851
		foreach ($crl['cert'] as $rcert) {
852
			if (cert_compare($rcert, $cert)) {
853
				return true;
854
			}
855
		}
856
	} else {
857
		foreach ($config['crl'] as $crl) {
858
			if (!is_array($crl['cert'])) {
859
				continue;
860
			}
861
			foreach ($crl['cert'] as $rcert) {
862
				if (cert_compare($rcert, $cert)) {
863
					return true;
864
				}
865
			}
866
		}
867
	}
868
	return false;
869
}
870

    
871
function is_openvpn_server_crl($crlref) {
872
	global $config;
873
	if (!is_array($config['openvpn']['openvpn-server'])) {
874
		return;
875
	}
876
	foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
877
		if (!empty($ovpns['crlref']) && ($ovpns['crlref'] == $crlref)) {
878
			return true;
879
		}
880
	}
881
	return false;
882
}
883

    
884
// Keep this general to allow for future expansion. See cert_in_use() above.
885
function crl_in_use($crlref) {
886
	return (is_openvpn_server_crl($crlref));
887
}
888

    
889
function is_crl_internal($crl) {
890
	return (!(!empty($crl['text']) && empty($crl['cert'])) || ($crl["method"] == "internal"));
891
}
892

    
893
function cert_get_cn($crt, $isref = false) {
894
	/* If this is a certref, not an actual cert, look up the cert first */
895
	if ($isref) {
896
		$cert = lookup_cert($crt);
897
		/* If it's not a valid cert, bail. */
898
		if (!(is_array($cert) && !empty($cert['crt']))) {
899
			return "";
900
		}
901
		$cert = $cert['crt'];
902
	} else {
903
		$cert = $crt;
904
	}
905
	$sub = cert_get_subject_array($cert);
906
	if (is_array($sub)) {
907
		foreach ($sub as $s) {
908
			if (strtoupper($s['a']) == "CN") {
909
				return $s['v'];
910
			}
911
		}
912
	}
913
	return "";
914
}
915

    
916
?>
(8-8/65)