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 Rubicon Communications, LLC (Netgate)
7
 * Copyright (c) 2008 Shrew Soft Inc. All rights reserved.
8
 * All rights reserved.
9
 *
10
 * Licensed under the Apache License, Version 2.0 (the "License");
11
 * you may not use this file except in compliance with the License.
12
 * You may obtain a copy of the License at
13
 *
14
 * http://www.apache.org/licenses/LICENSE-2.0
15
 *
16
 * Unless required by applicable law or agreed to in writing, software
17
 * distributed under the License is distributed on an "AS IS" BASIS,
18
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
 * See the License for the specific language governing permissions and
20
 * limitations under the License.
21
 */
22

    
23
define("OPEN_SSL_CONF_PATH", "/etc/ssl/openssl.cnf");
24

    
25
require_once("functions.inc");
26

    
27
global $openssl_digest_algs;
28
$openssl_digest_algs = array("sha1", "sha224", "sha256", "sha384", "sha512", "whirlpool");
29

    
30
global $openssl_crl_status;
31
$openssl_crl_status = array(
32
	OCSP_REVOKED_STATUS_NOSTATUS              => "No Status (default)",
33
	OCSP_REVOKED_STATUS_UNSPECIFIED           => "Unspecified",
34
	OCSP_REVOKED_STATUS_KEYCOMPROMISE         => "Key Compromise",
35
	OCSP_REVOKED_STATUS_CACOMPROMISE          => "CA Compromise",
36
	OCSP_REVOKED_STATUS_AFFILIATIONCHANGED    => "Affiliation Changed",
37
	OCSP_REVOKED_STATUS_SUPERSEDED            => "Superseded",
38
	OCSP_REVOKED_STATUS_CESSATIONOFOPERATION  => "Cessation of Operation",
39
	OCSP_REVOKED_STATUS_CERTIFICATEHOLD       => "Certificate Hold"
40
);
41

    
42
function & lookup_ca($refid) {
43
	global $config;
44

    
45
	if (is_array($config['ca'])) {
46
		foreach ($config['ca'] as & $ca) {
47
			if ($ca['refid'] == $refid) {
48
				return $ca;
49
			}
50
		}
51
	}
52

    
53
	return false;
54
}
55

    
56
function & lookup_ca_by_subject($subject) {
57
	global $config;
58

    
59
	if (is_array($config['ca'])) {
60
		foreach ($config['ca'] as & $ca) {
61
			$ca_subject = cert_get_subject($ca['crt']);
62
			if ($ca_subject == $subject) {
63
				return $ca;
64
			}
65
		}
66
	}
67

    
68
	return false;
69
}
70

    
71
function & lookup_cert($refid) {
72
	global $config;
73

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

    
82
	return false;
83
}
84

    
85
function & lookup_cert_by_name($name) {
86
	global $config;
87
	if (is_array($config['cert'])) {
88
		foreach ($config['cert'] as & $cert) {
89
			if ($cert['descr'] == $name) {
90
				return $cert;
91
			}
92
		}
93
	}
94
}
95

    
96
function & lookup_crl($refid) {
97
	global $config;
98

    
99
	if (is_array($config['crl'])) {
100
		foreach ($config['crl'] as & $crl) {
101
			if ($crl['refid'] == $refid) {
102
				return $crl;
103
			}
104
		}
105
	}
106

    
107
	return false;
108
}
109

    
110
function ca_chain_array(& $cert) {
111
	if ($cert['caref']) {
112
		$chain = array();
113
		$crt = lookup_ca($cert['caref']);
114
		$chain[] = $crt;
115
		while ($crt) {
116
			$caref = $crt['caref'];
117
			if ($caref) {
118
				$crt = lookup_ca($caref);
119
			} else {
120
				$crt = false;
121
			}
122
			if ($crt) {
123
				$chain[] = $crt;
124
			}
125
		}
126
		return $chain;
127
	}
128
	return false;
129
}
130

    
131
function ca_chain(& $cert) {
132
	if ($cert['caref']) {
133
		$ca = "";
134
		$cas = ca_chain_array($cert);
135
		if (is_array($cas)) {
136
			foreach ($cas as & $ca_cert) {
137
				$ca .= base64_decode($ca_cert['crt']);
138
				$ca .= "\n";
139
			}
140
		}
141
		return $ca;
142
	}
143
	return "";
144
}
145

    
146
function ca_import(& $ca, $str, $key = "", $serial = "") {
147
	global $config;
148

    
149
	$ca['crt'] = base64_encode($str);
150
	if (!empty($key)) {
151
		$ca['prv'] = base64_encode($key);
152
	}
153
	if (empty($serial)) {
154
		$ca['serial'] = 0;
155
	} else {
156
		$ca['serial'] = $serial;
157
	}
158
	$subject = cert_get_subject($str, false);
159
	$issuer = cert_get_issuer($str, false);
160

    
161
	// Find my issuer unless self-signed
162
	if ($issuer <> $subject) {
163
		$issuer_crt =& lookup_ca_by_subject($issuer);
164
		if ($issuer_crt) {
165
			$ca['caref'] = $issuer_crt['refid'];
166
		}
167
	}
168

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

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

    
191
	$args = array(
192
		"x509_extensions" => "v3_ca",
193
		"digest_alg" => $digest_alg,
194
		"private_key_bits" => (int)$keylen,
195
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
196
		"encrypt_key" => false);
197

    
198
	// generate a new key pair
199
	$res_key = openssl_pkey_new($args);
200
	if (!$res_key) {
201
		return false;
202
	}
203

    
204
	// generate a certificate signing request
205
	$res_csr = openssl_csr_new($dn, $res_key, $args);
206
	if (!$res_csr) {
207
		return false;
208
	}
209

    
210
	// self sign the certificate
211
	$res_crt = openssl_csr_sign($res_csr, null, $res_key, $lifetime, $args);
212
	if (!$res_crt) {
213
		return false;
214
	}
215

    
216
	// export our certificate data
217
	if (!openssl_pkey_export($res_key, $str_key) ||
218
	    !openssl_x509_export($res_crt, $str_crt)) {
219
		return false;
220
	}
221

    
222
	// return our ca information
223
	$ca['crt'] = base64_encode($str_crt);
224
	$ca['prv'] = base64_encode($str_key);
225
	$ca['serial'] = 0;
226

    
227
	return true;
228
}
229

    
230
function ca_inter_create(& $ca, $keylen, $lifetime, $dn, $caref, $digest_alg = "sha256") {
231
	// Create Intermediate Certificate Authority
232
	$signing_ca =& lookup_ca($caref);
233
	if (!$signing_ca) {
234
		return false;
235
	}
236

    
237
	$signing_ca_res_crt = openssl_x509_read(base64_decode($signing_ca['crt']));
238
	$signing_ca_res_key = openssl_pkey_get_private(array(0 => base64_decode($signing_ca['prv']) , 1 => ""));
239
	if (!$signing_ca_res_crt || !$signing_ca_res_key) {
240
		return false;
241
	}
242
	$signing_ca_serial = ++$signing_ca['serial'];
243

    
244
	$args = array(
245
		"x509_extensions" => "v3_ca",
246
		"digest_alg" => $digest_alg,
247
		"private_key_bits" => (int)$keylen,
248
		"private_key_type" => OPENSSL_KEYTYPE_RSA,
249
		"encrypt_key" => false);
250

    
251
	// generate a new key pair
252
	$res_key = openssl_pkey_new($args);
253
	if (!$res_key) {
254
		return false;
255
	}
256

    
257
	// generate a certificate signing request
258
	$res_csr = openssl_csr_new($dn, $res_key, $args);
259
	if (!$res_csr) {
260
		return false;
261
	}
262

    
263
	// Sign the certificate
264
	$res_crt = openssl_csr_sign($res_csr, $signing_ca_res_crt, $signing_ca_res_key, $lifetime, $args, $signing_ca_serial);
265
	if (!$res_crt) {
266
		return false;
267
	}
268

    
269
	// export our certificate data
270
	if (!openssl_pkey_export($res_key, $str_key) ||
271
	    !openssl_x509_export($res_crt, $str_crt)) {
272
		return false;
273
	}
274

    
275
	// return our ca information
276
	$ca['crt'] = base64_encode($str_crt);
277
	$ca['prv'] = base64_encode($str_key);
278
	$ca['serial'] = 0;
279
	$ca['caref'] = $caref;
280

    
281
	return true;
282
}
283

    
284
function cert_import(& $cert, $crt_str, $key_str) {
285

    
286
	$cert['crt'] = base64_encode($crt_str);
287
	$cert['prv'] = base64_encode($key_str);
288

    
289
	$subject = cert_get_subject($crt_str, false);
290
	$issuer = cert_get_issuer($crt_str, false);
291

    
292
	// Find my issuer unless self-signed
293
	if ($issuer <> $subject) {
294
		$issuer_crt =& lookup_ca_by_subject($issuer);
295
		if ($issuer_crt) {
296
			$cert['caref'] = $issuer_crt['refid'];
297
		}
298
	}
299
	return true;
300
}
301

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

    
304
	$cert['type'] = $type;
305

    
306
	if ($type != "self-signed") {
307
		$cert['caref'] = $caref;
308
		$ca =& lookup_ca($caref);
309
		if (!$ca) {
310
			return false;
311
		}
312

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

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

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

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

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

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

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

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

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

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

    
392
	return true;
393
}
394

    
395
function csr_generate(& $cert, $keylen, $dn, $digest_alg = "sha256") {
396

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

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

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

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

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

    
426
	return true;
427
}
428

    
429
function csr_complete(& $cert, $str_crt) {
430

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

    
435
	return true;
436
}
437

    
438
function csr_get_subject($str_crt, $decode = true) {
439

    
440
	if ($decode) {
441
		$str_crt = base64_decode($str_crt);
442
	}
443

    
444
	$components = openssl_csr_get_subject($str_crt);
445

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

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

    
459
	return $subject;
460
}
461

    
462
function cert_get_subject($str_crt, $decode = true) {
463

    
464
	if ($decode) {
465
		$str_crt = base64_decode($str_crt);
466
	}
467

    
468
	$inf_crt = openssl_x509_parse($str_crt);
469
	$components = $inf_crt['subject'];
470

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

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

    
489
	return $subject;
490
}
491

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

    
497
	if (!is_array($components)) {
498
		return;
499
	}
500

    
501
	$subject_array = array();
502

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

    
507
	return $subject_array;
508
}
509

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

    
516
function cert_get_issuer($str_crt, $decode = true) {
517

    
518
	if ($decode) {
519
		$str_crt = base64_decode($str_crt);
520
	}
521

    
522
	$inf_crt = openssl_x509_parse($str_crt);
523
	$components = $inf_crt['issuer'];
524

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

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

    
543
	return $issuer;
544
}
545

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

    
552
	$modulus = "";
553
	if (in_array($type, array("crt", "prv", "csr"))) {
554
		$type = str_replace(array("crt", "prv", "csr"), array("x509", "rsa", "req"), $type);
555
		$modulus = exec("echo \"{$str_crt}\" | openssl {$type} -noout -modulus");
556
	}
557
	return $modulus;
558
}
559

    
560
/* Same but returns modulus keysize not modulus itself */
561
function cert_get_modulus_keysize($str_crt, $decode = true, $type = "crt") {
562
	// modulus usually returned as "modulus=.....". Remove anything before an "=" and return 4 x (hex string length)
563
	$raw_modulus = explode('=', cert_get_modulus($str_crt, $decode, $type));
564
	return strlen(array_pop($raw_modulus))*4;
565
}
566

    
567
function csr_get_modulus($str_crt, $decode = true) {
568
	return cert_get_modulus($str_crt, $decode, "csr");
569
}
570

    
571
function cert_get_purpose($str_crt, $decode = true) {
572
	if ($decode) {
573
		$str_crt = base64_decode($str_crt);
574
	}
575
	$crt_details = openssl_x509_parse($str_crt);
576
	$purpose = array();
577
	$purpose['ca'] = (stristr($crt_details['extensions']['basicConstraints'], 'CA:TRUE') === false) ? 'No': 'Yes';
578
	$purpose['server'] = (strpos($crt_details['extensions']['nsCertType'], 'SSL Server') !== FALSE) ? 'Yes': 'No';
579
	return $purpose;
580
}
581

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

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

    
608
function prv_get_modulus($str_crt, $decode = true) {
609
	return cert_get_modulus($str_crt, $decode, "prv");
610
}
611

    
612
function is_openvpn_server_ca($caref) {
613
	global $config;
614
	if (!is_array($config['openvpn']['openvpn-server'])) {
615
		return;
616
	}
617
	foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
618
		if ($ovpns['caref'] == $caref) {
619
			return true;
620
		}
621
	}
622
	return false;
623
}
624

    
625
function is_openvpn_client_ca($caref) {
626
	global $config;
627
	if (!is_array($config['openvpn']['openvpn-client'])) {
628
		return;
629
	}
630
	foreach ($config['openvpn']['openvpn-client'] as $ovpnc) {
631
		if ($ovpnc['caref'] == $caref) {
632
			return true;
633
		}
634
	}
635
	return false;
636
}
637

    
638
function is_ipsec_peer_ca($caref) {
639
	global $config;
640
	if (!is_array($config['ipsec']['phase1'])) {
641
		return;
642
	}
643
	foreach ($config['ipsec']['phase1'] as $ipsec) {
644
		if ($ipsec['caref'] == $caref) {
645
			return true;
646
		}
647
	}
648
	return false;
649
}
650

    
651
function is_ldap_peer_ca($caref) {
652
	global $config;
653
	if (!is_array($config['system']['authserver'])) {
654
		return;
655
	}
656
	foreach ($config['system']['authserver'] as $authserver) {
657
		if ($authserver['ldap_caref'] == $caref) {
658
			return true;
659
		}
660
	}
661
	return false;
662
}
663

    
664
function ca_in_use($caref) {
665
	return (is_openvpn_server_ca($caref) ||
666
		is_openvpn_client_ca($caref) ||
667
		is_ipsec_peer_ca($caref) ||
668
		is_ldap_peer_ca($caref));
669
}
670

    
671
function is_user_cert($certref) {
672
	global $config;
673
	if (!is_array($config['system']['user'])) {
674
		return;
675
	}
676
	foreach ($config['system']['user'] as $user) {
677
		if (!is_array($user['cert'])) {
678
			continue;
679
		}
680
		foreach ($user['cert'] as $cert) {
681
			if ($certref == $cert) {
682
				return true;
683
			}
684
		}
685
	}
686
	return false;
687
}
688

    
689
function is_openvpn_server_cert($certref) {
690
	global $config;
691
	if (!is_array($config['openvpn']['openvpn-server'])) {
692
		return;
693
	}
694
	foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
695
		if ($ovpns['certref'] == $certref) {
696
			return true;
697
		}
698
	}
699
	return false;
700
}
701

    
702
function is_openvpn_client_cert($certref) {
703
	global $config;
704
	if (!is_array($config['openvpn']['openvpn-client'])) {
705
		return;
706
	}
707
	foreach ($config['openvpn']['openvpn-client'] as $ovpnc) {
708
		if ($ovpnc['certref'] == $certref) {
709
			return true;
710
		}
711
	}
712
	return false;
713
}
714

    
715
function is_ipsec_cert($certref) {
716
	global $config;
717
	if (!is_array($config['ipsec']['phase1'])) {
718
		return;
719
	}
720
	foreach ($config['ipsec']['phase1'] as $ipsec) {
721
		if ($ipsec['certref'] == $certref) {
722
			return true;
723
		}
724
	}
725
	return false;
726
}
727

    
728
function is_webgui_cert($certref) {
729
	global $config;
730
	if (($config['system']['webgui']['ssl-certref'] == $certref) &&
731
	    ($config['system']['webgui']['protocol'] != "http")) {
732
		return true;
733
	}
734
}
735

    
736
function is_package_cert($certref) {
737
	$pluginparams = array();
738
	$pluginparams['type'] = 'certificates';
739
	$pluginparams['event'] = 'used_certificates';
740

    
741
	$certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
742

    
743
	/* Check if any package is using certificate */
744
	foreach ($certificates_used_by_packages as $name => $package) {
745
		if (is_array($package['certificatelist'][$certref]) &&
746
		    isset($package['certificatelist'][$certref]) > 0) {
747
			return true;
748
		}
749
	}
750
}
751

    
752
function is_captiveportal_cert($certref) {
753
	global $config;
754
	if (!is_array($config['captiveportal'])) {
755
		return;
756
	}
757
	foreach ($config['captiveportal'] as $portal) {
758
		if (isset($portal['enable']) && isset($portal['httpslogin']) && ($portal['certref'] == $certref)) {
759
			return true;
760
		}
761
	}
762
	return false;
763
}
764

    
765
function cert_in_use($certref) {
766

    
767
	return (is_webgui_cert($certref) ||
768
		is_user_cert($certref) ||
769
		is_openvpn_server_cert($certref) ||
770
		is_openvpn_client_cert($certref) ||
771
		is_ipsec_cert($certref) ||
772
		is_captiveportal_cert($certref) ||
773
		is_package_cert($certref));
774
}
775

    
776
function crl_create(& $crl, $caref, $name, $serial = 0, $lifetime = 9999) {
777
	global $config;
778
	$ca =& lookup_ca($caref);
779
	if (!$ca) {
780
		return false;
781
	}
782
	$crl['descr'] = $name;
783
	$crl['caref'] = $caref;
784
	$crl['serial'] = $serial;
785
	$crl['lifetime'] = $lifetime;
786
	$crl['cert'] = array();
787
	$crl_res = crl_update($crl);
788
	$config['crl'][] = $crl;
789
	return $crl_res;
790
}
791

    
792
function crl_update(& $crl) {
793
	global $config;
794
	$ca =& lookup_ca($crl['caref']);
795
	if (!$ca) {
796
		return false;
797
	}
798
	// If we have text but no certs, it was imported and cannot be updated.
799
	if (($crl["method"] != "internal") && (!empty($crl['text']) && empty($crl['cert']))) {
800
		return false;
801
	}
802
	$crl['serial']++;
803
	$ca_str_crt = base64_decode($ca['crt']);
804
	$ca_str_key = base64_decode($ca['prv']);
805
	$crl_res = openssl_crl_new($ca_str_crt, $crl['serial'], $crl['lifetime']);
806
	if (is_array($crl['cert']) && (count($crl['cert']) > 0)) {
807
		foreach ($crl['cert'] as $cert) {
808
			openssl_crl_revoke_cert($crl_res, base64_decode($cert["crt"]), $cert["revoke_time"], $cert["reason"]);
809
		}
810
	}
811
	openssl_crl_export($crl_res, $crl_text, $ca_str_key);
812
	$crl['text'] = base64_encode($crl_text);
813
	return $crl_res;
814
}
815

    
816
function cert_revoke($cert, & $crl, $reason = OCSP_REVOKED_STATUS_UNSPECIFIED) {
817
	global $config;
818
	if (is_cert_revoked($cert, $crl['refid'])) {
819
		return true;
820
	}
821
	// If we have text but no certs, it was imported and cannot be updated.
822
	if (!is_crl_internal($crl)) {
823
		return false;
824
	}
825
	$cert["reason"] = $reason;
826
	$cert["revoke_time"] = time();
827
	$crl["cert"][] = $cert;
828
	crl_update($crl);
829
	return true;
830
}
831

    
832
function cert_unrevoke($cert, & $crl) {
833
	global $config;
834
	if (!is_crl_internal($crl)) {
835
		return false;
836
	}
837
	foreach ($crl['cert'] as $id => $rcert) {
838
		if (($rcert['refid'] == $cert['refid']) || ($rcert['descr'] == $cert['descr'])) {
839
			unset($crl['cert'][$id]);
840
			if (count($crl['cert']) == 0) {
841
				// Protect against accidentally switching the type to imported, for older CRLs
842
				if (!isset($crl['method'])) {
843
					$crl['method'] = "internal";
844
				}
845
				crl_update($crl);
846
			} else {
847
				crl_update($crl);
848
			}
849
			return true;
850
		}
851
	}
852
	return false;
853
}
854

    
855
/* Compare two certificates to see if they match. */
856
function cert_compare($cert1, $cert2) {
857
	/* Ensure two certs are identical by first checking that their issuers match, then
858
		subjects, then serial numbers, and finally the moduli. Anything less strict
859
		could accidentally count two similar, but different, certificates as
860
		being identical. */
861
	$c1 = base64_decode($cert1['crt']);
862
	$c2 = base64_decode($cert2['crt']);
863
	if ((cert_get_issuer($c1, false) == cert_get_issuer($c2, false)) &&
864
	    (cert_get_subject($c1, false) == cert_get_subject($c2, false)) &&
865
	    (cert_get_serial($c1, false) == cert_get_serial($c2, false)) &&
866
	    (cert_get_modulus($c1, false) == cert_get_modulus($c2, false))) {
867
		return true;
868
	}
869
	return false;
870
}
871

    
872
function is_cert_revoked($cert, $crlref = "") {
873
	global $config;
874
	if (!is_array($config['crl'])) {
875
		return false;
876
	}
877

    
878
	if (!empty($crlref)) {
879
		$crl = lookup_crl($crlref);
880
		if (!is_array($crl['cert'])) {
881
			return false;
882
		}
883
		foreach ($crl['cert'] as $rcert) {
884
			if (cert_compare($rcert, $cert)) {
885
				return true;
886
			}
887
		}
888
	} else {
889
		foreach ($config['crl'] as $crl) {
890
			if (!is_array($crl['cert'])) {
891
				continue;
892
			}
893
			foreach ($crl['cert'] as $rcert) {
894
				if (cert_compare($rcert, $cert)) {
895
					return true;
896
				}
897
			}
898
		}
899
	}
900
	return false;
901
}
902

    
903
function is_openvpn_server_crl($crlref) {
904
	global $config;
905
	if (!is_array($config['openvpn']['openvpn-server'])) {
906
		return;
907
	}
908
	foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
909
		if (!empty($ovpns['crlref']) && ($ovpns['crlref'] == $crlref)) {
910
			return true;
911
		}
912
	}
913
	return false;
914
}
915

    
916
// Keep this general to allow for future expansion. See cert_in_use() above.
917
function crl_in_use($crlref) {
918
	return (is_openvpn_server_crl($crlref));
919
}
920

    
921
function is_crl_internal($crl) {
922
	return (!(!empty($crl['text']) && empty($crl['cert'])) || ($crl["method"] == "internal"));
923
}
924

    
925
function cert_get_cn($crt, $isref = false) {
926
	/* If this is a certref, not an actual cert, look up the cert first */
927
	if ($isref) {
928
		$cert = lookup_cert($crt);
929
		/* If it's not a valid cert, bail. */
930
		if (!(is_array($cert) && !empty($cert['crt']))) {
931
			return "";
932
		}
933
		$cert = $cert['crt'];
934
	} else {
935
		$cert = $crt;
936
	}
937
	$sub = cert_get_subject_array($cert);
938
	if (is_array($sub)) {
939
		foreach ($sub as $s) {
940
			if (strtoupper($s['a']) == "CN") {
941
				return $s['v'];
942
			}
943
		}
944
	}
945
	return "";
946
}
947

    
948
?>
(4-4/51)