commit 263089306c0f6a8dedeb44fd7c7c5658b527f7d5
Author: Marcos Mendoza <mmendoza@netgate.com>
Date:   Fri Mar 29 11:53:58 2024 -0600

    Use config accessors in certificate functions

diff --git a/src/etc/inc/auth.inc b/src/etc/inc/auth.inc
index 7631d6dcd3..ea7ee680b3 100644
--- a/src/etc/inc/auth.inc
+++ b/src/etc/inc/auth.inc
@@ -1119,6 +1119,7 @@ function ldap_setup_caenv($ldap, $authcfg) {
 		ldap_set_option($ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_HARD);
 	} else {
 		$caref = lookup_ca($authcfg['ldap_caref']);
+		$caref = $caref['item'];
 		$cert_details = openssl_x509_parse(base64_decode($caref['crt']));
 		$param = array('caref' => $authcfg['ldap_caref']);
 		$cachain = ca_chain($param);
diff --git a/src/etc/inc/captiveportal.inc b/src/etc/inc/captiveportal.inc
index a7a3e491e5..940062be6f 100644
--- a/src/etc/inc/captiveportal.inc
+++ b/src/etc/inc/captiveportal.inc
@@ -448,6 +448,7 @@ function captiveportal_init_webgui_zone($cpcfg) {
 
 	if (isset($cpcfg['httpslogin'])) {
 		$cert = lookup_cert($cpcfg['certref']);
+		$cert = $cert['item'];
 		$crt = base64_decode($cert['crt']);
 		$key = base64_decode($cert['prv']);
 		$ca = ca_chain($cert);
diff --git a/src/etc/inc/certs.inc b/src/etc/inc/certs.inc
index 9827a1408c..e9bc65466a 100644
--- a/src/etc/inc/certs.inc
+++ b/src/etc/inc/certs.inc
@@ -64,98 +64,108 @@ $cert_max_lifetime = 12000;
 global $crl_max_lifetime;
 $crl_max_lifetime = 9999;
 
-function & lookup_ca($refid) {
-	global $config;
-
-	if (is_array($config['ca'])) {
-		foreach ($config['ca'] as & $ca) {
-			if (empty($ca)) {
-				continue;
-			}
-			if ($ca['refid'] == $refid) {
-				return $ca;
-			}
+/**
+ * @return array Contains the CA config index and item.
+ */
+function lookup_ca($refid) {
+	$ca_item = ['idx' => null, 'item' => null];
+	foreach (config_get_path('ca', []) as $idx => $ca) {
+		if (empty($ca)) {
+			continue;
+		}
+		if ($ca['refid'] == $refid) {
+			$ca_item = ['idx' => $idx, 'item' => $ca];
+			break;
 		}
 	}
 
-	return false;
+	return $ca_item;
 }
 
-function & lookup_ca_by_subject($subject) {
-	global $config;
-
-	if (is_array($config['ca'])) {
-		foreach ($config['ca'] as & $ca) {
-			if (empty($ca)) {
-				continue;
-			}
-			$ca_subject = cert_get_subject($ca['crt']);
-			if ($ca_subject == $subject) {
-				return $ca;
-			}
+/**
+ * @return array Contains the CA config index and item.
+ */
+function lookup_ca_by_subject($subject) {
+	$ca_item = ['idx' => null, 'item' => null];
+	foreach (config_get_path('ca', []) as $idx => $ca) {
+		if (empty($ca)) {
+			continue;
+		}
+		$ca_subject = cert_get_subject($ca['crt']);
+		if ($ca_subject == $subject) {
+			$ca_item = ['idx' => $idx, 'item' => $ca];
+			break;
 		}
 	}
 
-	return false;
+	return $ca_item;
 }
 
-function & lookup_cert($refid) {
-	global $config;
-
-	if (is_array($config['cert'])) {
-		foreach ($config['cert'] as & $cert) {
-			if (empty($cert)) {
-				continue;
-			}
-			if ($cert['refid'] == $refid) {
-				return $cert;
-			}
+/**
+ * @return array Contains the cert config index and item.
+ */
+function lookup_cert($refid) {
+	$cert_item = ['idx' => null, 'item' => null];
+	foreach (config_get_path('cert', []) as $idx => $cert) {
+		if (empty($cert)) {
+			continue;
+		}
+		if ($cert['refid'] == $refid) {
+			$cert_item = ['idx' => $idx, 'item' => $cert];
+			break;
 		}
 	}
 
-	return false;
+	return $cert_item;
 }
 
-function & lookup_cert_by_name($name) {
-	global $config;
-	if (is_array($config['cert'])) {
-		foreach ($config['cert'] as & $cert) {
-			if (empty($cert)) {
-				continue;
-			}
-			if ($cert['descr'] == $name) {
-				return $cert;
-			}
+/**
+ * @return array Contains the cert config index and item.
+ */
+function lookup_cert_by_name($name) {
+	$cert_item = ['idx' => null, 'item' => null];
+	foreach (config_get_path('cert', []) as $idx => $cert) {
+		if (empty($cert)) {
+			continue;
+		}
+		if ($cert['descr'] == $name) {
+			$cert_item = ['idx' => $idx, 'item' => $cert];
+			break;
 		}
 	}
-}
 
-function & lookup_crl($refid) {
-	global $config;
+	return $cert_item;
+}
 
-	if (is_array($config['crl'])) {
-		foreach ($config['crl'] as & $crl) {
-			if (empty($crl)) {
-				continue;
-			}
-			if ($crl['refid'] == $refid) {
-				return $crl;
-			}
+/**
+ * @return array Contains the CRL config index and item.
+ */
+function lookup_crl($refid) {
+	$crl_item = ['idx' => null, 'item' => null];
+	foreach (config_get_path('crl', []) as $idx => $crl) {
+		if (empty($crl)) {
+			continue;
+		}
+		if ($crl['refid'] == $refid) {
+			$crl_item = ['idx' => $idx, 'item' => $crl];
+			break;
 		}
 	}
 
-	return false;
+	return $crl_item;
 }
 
-function ca_chain_array(& $cert) {
+function ca_chain_array($cert) {
 	if ($cert['caref']) {
 		$chain = array();
 		$crt = lookup_ca($cert['caref']);
+		$crt = $crt['item'];
 		$chain[] = $crt;
 		while ($crt) {
 			$caref = $crt['caref'];
 			if ($caref) {
 				$crt = lookup_ca($caref);
+				$crt = $crt['item'];
 			} else {
 				$crt = false;
 			}
@@ -168,12 +178,12 @@ function ca_chain_array(& $cert) {
 	return false;
 }
 
-function ca_chain(& $cert) {
+function ca_chain($cert) {
 	if ($cert['caref']) {
 		$ca = "";
 		$cas = ca_chain_array($cert);
 		if (is_array($cas)) {
-			foreach ($cas as & $ca_cert) {
+			foreach ($cas as $ca_cert) {
 				$ca .= base64_decode($ca_cert['crt']);
 				$ca .= "\n";
 			}
@@ -183,9 +193,17 @@ function ca_chain(& $cert) {
 	return "";
 }
 
+/**
+ * Writes the given CA to config and updates certs that reference it.
+ * 
+ * @param array  &$ca    Directly modified; written to config if it does not exist.
+ * @param string $str    CA cert - not encoded.
+ * @param string $key    Optional. CA key - not encoded.
+ * @param string $serial Optional. CA serial; defaults to 0.
+ * 
+ * @return bool False if CA already exists; True otherwise.
+ */
 function ca_import(& $ca, $str, $key = "", $serial = "") {
-	global $config;
-
 	$ca['crt'] = base64_encode($str);
 	if (!empty($key)) {
 		$ca['prv'] = base64_encode($key);
@@ -201,33 +219,34 @@ function ca_import(& $ca, $str, $key = "", $serial = "") {
 
 	// Find my issuer unless self-signed
 	if ($issuer <> $subject) {
-		$issuer_crt =& lookup_ca_by_subject($issuer);
+		$issuer_crt = lookup_ca_by_subject($issuer);
+		$issuer_crt = $issuer_crt['item'];
 		if ($issuer_crt) {
 			$ca['caref'] = $issuer_crt['refid'];
 		}
 	}
 
 	/* Correct if child certificate was loaded first */
-	if (is_array($config['ca'])) {
-		foreach ($config['ca'] as & $oca) {
-			// check by serial number if CA already exists
-			$osn = cert_get_serial($oca['crt']);
-			if (($ca['refid'] <> $oca['refid']) && ($serialNumber == $osn)) {
-				return false;
-			}
-			$issuer = cert_get_issuer($oca['crt']);
-			if (($ca['refid'] <> $oca['refid']) && ($issuer == $subject)) {
-				$oca['caref'] = $ca['refid'];
-			}
+	foreach (config_get_path('ca', []) as $idx => $oca) {
+		// check by serial number if CA already exists
+		$osn = cert_get_serial($oca['crt']);
+		if (($ca['refid'] <> $oca['refid']) && ($serialNumber == $osn)) {
+			return false;
+		}
+		$issuer = cert_get_issuer($oca['crt']);
+		if (($ca['refid'] <> $oca['refid']) && ($issuer == $subject)) {
+			config_set_path("ca/{$idx}/caref", $ca['refid']);
 		}
 	}
-	if (is_array($config['cert'])) {
-		foreach ($config['cert'] as & $cert) {
+	$cert_config = config_get_path('cert');
+	if (is_array($cert_config)) {
+		foreach ($cert_config as & $cert) {
 			$issuer = cert_get_issuer($cert['crt']);
 			if ($issuer == $subject) {
 				$cert['caref'] = $ca['refid'];
 			}
 		}
+		config_set_path('cert', $cert_config);
 	}
 	return true;
 }
@@ -278,9 +297,13 @@ function ca_create(& $ca, $keylen, $lifetime, $dn, $digest_alg = "sha256", $keyt
 	return true;
 }
 
+/**
+ * Creates intermediate Certificate Authority; increments the CA's serial and writes it to config.
+ */
 function ca_inter_create(& $ca, $keylen, $lifetime, $dn, $caref, $digest_alg = "sha256", $keytype = "RSA", $ecname = "prime256v1") {
 	// Create Intermediate Certificate Authority
-	$signing_ca =& lookup_ca($caref);
+	$ca_item_config = lookup_ca($caref);
+	$signing_ca = &$ca_item_config['item'];
 	if (!$signing_ca) {
 		return false;
 	}
@@ -290,7 +313,7 @@ function ca_inter_create(& $ca, $keylen, $lifetime, $dn, $caref, $digest_alg = "
 	if (!$signing_ca_res_crt || !$signing_ca_res_key) {
 		return false;
 	}
-	$signing_ca_serial = ++$signing_ca['serial'];
+	$signing_ca_serial = config_set_path("ca/{$ca_item_config['idx']}", ++$signing_ca['serial']);
 
 	$args = array(
 		"x509_extensions" => "v3_ca",
@@ -347,7 +370,8 @@ function cert_import(& $cert, $crt_str, $key_str) {
 
 	// Find my issuer unless self-signed
 	if ($issuer <> $subject) {
-		$issuer_crt =& lookup_ca_by_subject($issuer);
+		$issuer_crt = lookup_ca_by_subject($issuer);
+		$issuer_crt = $issuer_crt['item'];
 		if ($issuer_crt) {
 			$cert['caref'] = $issuer_crt['refid'];
 		}
@@ -361,7 +385,8 @@ function cert_create(& $cert, $caref, $keylen, $lifetime, $dn, $type = "user", $
 
 	if ($type != "self-signed") {
 		$cert['caref'] = $caref;
-		$ca =& lookup_ca($caref);
+		$ca_item_config = lookup_ca($caref);
+		$ca = &$ca_item_config['item'];
 		if (!$ca) {
 			return false;
 		}
@@ -376,6 +401,7 @@ function cert_create(& $cert, $caref, $keylen, $lifetime, $dn, $type = "user", $
 
 		/* Get the next available CA serial number. */
 		$ca_serial = ca_get_next_serial($ca);
+		config_set_path("ca/{$ca_item_config['idx']}", $ca);
 	}
 
 	$cert_type = cert_type_config_section($type);
@@ -408,6 +434,7 @@ function cert_create(& $cert, $caref, $keylen, $lifetime, $dn, $type = "user", $
 
 	// If this is a self-signed cert, blank out the CA and sign with the cert's key
 	if ($type == "self-signed") {
+		config_del_path("ca/{$ca_item_config['idx']}");
 		$ca           = null;
 		$ca_res_crt   = null;
 		$ca_res_key   = $res_key;
@@ -984,10 +1011,14 @@ function crl_get_max_lifetime() {
 	return min(7000, cert_get_max_lifetime());
 }
 
+/**
+ * Directly modifes the Certificate Revocation List and adds it to config.
+ */
 function crl_create(& $crl, $caref, $name, $serial = 0, $lifetime = 3650) {
 	global $config;
 	$max_lifetime = crl_get_max_lifetime();
-	$ca =& lookup_ca($caref);
+	$ca = lookup_ca($caref);
+	$ca = $ca['item'];
 	if (!$ca) {
 		return false;
 	}
@@ -1003,7 +1034,11 @@ function crl_create(& $crl, $caref, $name, $serial = 0, $lifetime = 3650) {
 	return $crl;
 }
 
-function crl_update(& $crl) {
+/**
+ * @param array &$crl_config Must contain the CRL config index and item.
+ */
+function crl_update(& $crl_config) {
+	$crl = &$crl_config['item'];
 	require_once('ASN1.php');
 	require_once('ASN1_UTF8STRING.php');
 	require_once('ASN1_ASCIISTRING.php');
@@ -1027,7 +1062,8 @@ function crl_update(& $crl) {
 
 	global $config;
 	$max_lifetime = crl_get_max_lifetime();
-	$ca =& lookup_ca($crl['caref']);
+	$ca = lookup_ca($crl['caref']);
+	$ca = $ca['item'];
 	if (!$ca) {
 		return false;
 	}
@@ -1036,6 +1072,7 @@ function crl_update(& $crl) {
 		return false;
 	}
 	$crl['serial']++;
+	config_set_path("crl/{$crl_config['idx']}", $crl);
 	$ca_cert = \Ukrbublik\openssl_x509_crl\X509::pem2der(base64_decode($ca['crt']));
 	$ca_pkey = openssl_pkey_get_private(base64_decode($ca['prv']));
 
@@ -1067,12 +1104,18 @@ function crl_update(& $crl) {
 
 	$crl_data = \Ukrbublik\openssl_x509_crl\X509_CRL::create($crlconf, $ca_pkey, $ca_cert);
 	$crl['text'] = base64_encode(\Ukrbublik\openssl_x509_crl\X509::der2pem4crl($crl_data));
+	config_set_path("crl/{$crl_config['idx']}", $crl);
 
 	return $crl['text'];
 }
 
-function cert_revoke($cert, & $crl, $reason = -1) {
-	global $config;
+/**
+ * @param array|string $cert        The cert item or cert serial to revoke.
+ * @param array        &$crl_config Must contain the CRL config index and item.
+ * @param int          $reason      Revocation reason; defined by RFC5280.
+ */
+function cert_revoke($cert, &$crl_config, $reason = -1) {
+	$crl = &$crl_config['item'];
 	if (is_cert_revoked($cert, $crl['refid'])) {
 		return true;
 	}
@@ -1095,12 +1138,16 @@ function cert_revoke($cert, & $crl, $reason = -1) {
 	$rcert['reason'] = $reason;
 	$rcert['revoke_time'] = time();
 	$crl['cert'][] = $rcert;
-	crl_update($crl);
+	crl_update($crl_config);
 	return true;
 }
 
-function cert_unrevoke($cert, & $crl) {
-	global $config;
+/**
+ * @param array|string $cert        The cert item or cert serial to unrevoke.
+ * @param array        &$crl_config Must contain the CRL config index and item.
+ */
+function cert_unrevoke($cert, &$crl_config) {
+	$crl = &$crl_config['item'];
 	if (!is_crl_internal($crl)) {
 		return false;
 	}
@@ -1118,9 +1165,9 @@ function cert_unrevoke($cert, & $crl) {
 				if (!isset($crl['method'])) {
 					$crl['method'] = "internal";
 				}
-				crl_update($crl);
+				crl_update($crl_config);
 			} else {
-				crl_update($crl);
+				crl_update($crl_config);
 			}
 			return true;
 		}
@@ -1272,6 +1319,7 @@ function ca_has_serial($caref, $serial) {
 
 	/* Check the CA itself */
 	$this_ca = lookup_ca($caref);
+	$this_ca = $this_ca['item'];
 	$this_serial = cert_get_serial($this_ca['crt'], true);
 	if ($serial == $this_serial) {
 		return true;
@@ -1368,6 +1416,7 @@ function crl_contains_cert($crl, $cert) {
 
 	/* Find the issuer of this CRL */
 	$ca = lookup_ca($crl['caref']);
+	$ca = $ca['item'];
 	$crlissuer = is_array($cert) ? cert_get_subject($ca['crt']) : null;
 	$serial = crl_get_entry_serial($cert);
 
@@ -1411,6 +1460,7 @@ function is_cert_revoked($cert, $crlref = "") {
 
 	if (!empty($crlref)) {
 		$crl = lookup_crl($crlref);
+		$crl = $crl['item'];
 		return crl_contains_cert($crl, $cert);
 	} else {
 		if (!is_array($cert)) {
@@ -1472,6 +1522,7 @@ function cert_get_cn($crt, $isref = false) {
 	/* If this is a certref, not an actual cert, look up the cert first */
 	if ($isref) {
 		$cert = lookup_cert($crt);
+		$cert = $cert['item'];
 		/* If it's not a valid cert, bail. */
 		if (!(is_array($cert) && !empty($cert['crt']))) {
 			return "";
@@ -1566,6 +1617,7 @@ function is_cert_locally_renewable($cert) {
 	$ca = array();
 	if (!empty($cert['caref'])) {
 		$ca = lookup_ca($cert['caref']);
+		$ca = $ca['item'];
 	}
 
 	/* If the CA exists and we have the private key, or if the cert is
@@ -1590,7 +1642,8 @@ $cert_strict_values = array(
  * NAME
  *   cert_renew - Renew an existing internal CA or certificate
  * INPUTS
- *   $cert : The entry to be renewed (used as a reference so it can be altered directly)
+ *   $cert_config : An array containing the config array path and the ca or
+ *                  cert item; it is modified directly and written to config.
  *   $reusekey : Whether or not to reuse the existing key for the certificate
  *      true: Reuse the existing key (Default)
  *      false: Generate a new key based on current (or enforced minimum) parameters
@@ -1605,9 +1658,10 @@ $cert_strict_values = array(
  *   Does NOT run write_config(), that must be performed by the caller.
  ******/
 
-function cert_renew(& $cert, $reusekey = true, $strictsecurity = false, $reuseserial = false) {
+function cert_renew(& $cert_config, $reusekey = true, $strictsecurity = false, $reuseserial = false) {
 	global $cert_strict_values, $cert_curve_compatible, $curve_compatible_list;
 
+	$cert = &$cert_config['item'];
 	/* If there is no certificate or private key string, this entry is either
 	 *  invalid or cannot be renewed by this function. */
 	if (empty($cert['crt']) || empty($cert['prv'])) {
@@ -1662,6 +1716,7 @@ function cert_renew(& $cert, $reusekey = true, $strictsecurity = false, $reusese
 		/* Automatically determine certificate type if unset based on purpose value */
 		$cert['type'] = ($purpose['server'] == 'Yes') ? 'server' : 'user';
 	}
+	config_set_path("{$cert_config['path']}", $cert);
 
 	/* Convert the internal certificate type to an openssl.cnf section name */
 	$cert_type = cert_type_config_section($cert['type']);
@@ -1763,7 +1818,8 @@ function cert_renew(& $cert, $reusekey = true, $strictsecurity = false, $reusese
 
 	if (!empty($cert['caref'])) {
 		/* The certificate was signed by a CA, so read the CA details. */
-		$ca = & lookup_ca($cert['caref']);
+		$ca_item_config = lookup_ca($cert['caref']);
+		$ca = &$ca_item_config['item'];
 		/* If the referenced CA cannot be found, bail. */
 		if (!$ca) {
 			return false;
@@ -1782,6 +1838,10 @@ function cert_renew(& $cert, $reusekey = true, $strictsecurity = false, $reusese
 		}
 		/* Get the next available CA serial number. */
 		$ca_serial = ca_get_next_serial($ca);
+		config_set_path("ca/{$ca_item_config['idx']}", $ca);
+		if ($cert['type'] == 'ca') {
+			$cert = $ca;
+		}
 	} elseif ($selfsigned) {
 		/* For self-signed CAs & certificates, set the CA details to self and
 		 * use the key for this entry to sign itself.
@@ -1812,6 +1872,7 @@ function cert_renew(& $cert, $reusekey = true, $strictsecurity = false, $reusese
 	/* Load the new certificate string and key into the configuration */
 	$cert['crt'] = base64_encode($str_crt);
 	$cert['prv'] = base64_encode($str_key);
+	config_set_path("{$cert_config['path']}", $cert);
 
 	return true;
 }
@@ -2735,6 +2796,7 @@ function cert_pkcs12_export($cert, $encryption = 'high', $passphrase = '', $add_
 	$eca = '';
 	if ($add_ca && !empty($cert['caref'])) {
 		$ca = lookup_ca($cert['caref']);
+		$ca = $ca['item'];
 		if ($ca) {
 			$capath = "{$workdir}/ca.pem";
 			file_put_contents($capath, base64_decode($ca['crt']));
@@ -2805,6 +2867,7 @@ function cert_chain_has_weak_digest($cert) {
 	/* Check CA if present */
 	if (!empty($cert['caref'])) {
 		$ca = lookup_ca($cert['caref']);
+		$ca = $ca['item'];
 		$weak = cert_has_weak_digest($ca['crt']);
 	}
 	/* Only check cert if the CA is not weak (or no self-signed) */
diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc
index 9beebeafe4..dd3c5708c0 100644
--- a/src/etc/inc/interfaces.inc
+++ b/src/etc/inc/interfaces.inc
@@ -3461,6 +3461,7 @@ EOD;
 					}
 					if (strstr($wlcfg['wpa']['wpa_eap_client_mode'], 'TLS')) {
 						$cert = lookup_cert($wlcfg['wpa']['wpa_eap_cert']);
+						$cert = $cert['item'];
 						$wpa_supplicant_crt = $wpa_supplicant_file . "crt";
 						$wpa_supplicant_key = $wpa_supplicant_file . "key";
 						@file_put_contents($wpa_supplicant_crt, base64_decode($cert['crt']) . "\n" .
@@ -3472,6 +3473,7 @@ EOD;
 						$wpa .= "private_key=\"{$wpa_supplicant_key}\"\n";
 					}
 					$ca = lookup_ca($wlcfg['wpa']['wpa_eap_ca']);
+					$ca = $ca['item'];
 					$wpa_supplicant_ca = $wpa_supplicant_file . "ca";
 					@file_put_contents($wpa_supplicant_ca, base64_decode($ca['crt']) . "\n" .
 					    ca_chain($ca));
diff --git a/src/etc/inc/ipsec.inc b/src/etc/inc/ipsec.inc
index cbac28bf5d..2fcab55ff8 100644
--- a/src/etc/inc/ipsec.inc
+++ b/src/etc/inc/ipsec.inc
@@ -2144,6 +2144,7 @@ function ipsec_setup_authentication(& $ph1ent, & $conn) {
 
 	if (!empty($ph1ent['caref'])) {
 		$ca = lookup_ca($ph1ent['caref']);
+		$ca = $ca['item'];
 		if ($ca) {
 			/* Get hash value to use for filename */
 			$ca_details = openssl_x509_parse(base64_decode($ca['crt']));
@@ -2903,6 +2904,7 @@ function ipsec_setup_secrets() {
 
 			$ikeid = $ph1ent['ikeid'];
 			$cert = lookup_cert($ph1ent['certref']);
+			$cert = $cert['item'];
 
 			if (!$cert) {
 				log_error(sprintf(gettext("Error: Invalid phase1 certificate reference for %s"), $ph1ent['name']));
@@ -2989,6 +2991,7 @@ function ipsec_setup_secrets() {
 		    array('cert', 'eap-tls', 'xauth_cert_server', 'pkcs11'))) {
 			if (!empty($ph1ent['caref']) && !array_key_exists($ph1ent['caref'], $vpncas)) {
 				$thisca = lookup_ca($ph1ent['caref']);
+				$thisca = $thisca['item'];
 				$vpncas[$ph1ent['caref']] = $thisca;
 				/* follow chain up to root */
 				$cachain = ca_chain_array($thisca);
diff --git a/src/etc/inc/openvpn.inc b/src/etc/inc/openvpn.inc
index ebf2f715d7..e8a259ec16 100644
--- a/src/etc/inc/openvpn.inc
+++ b/src/etc/inc/openvpn.inc
@@ -280,13 +280,12 @@ function openvpn_build_if_list() {
 }
 
 function openvpn_build_crl_list() {
-	global $a_crl;
-
 	$list = array('' => 'None');
 
-	foreach ($a_crl as $crl) {
+	foreach (config_get_path('crl', []) as $crl) {
 		$caname = "";
 		$ca = lookup_ca($crl['caref']);
+		$ca = $ca['item'];
 
 		if ($ca) {
 			$caname = " (CA: {$ca['descr']})";
@@ -299,7 +298,6 @@ function openvpn_build_crl_list() {
 }
 
 function openvpn_build_cert_list($include_none = false, $prioritize_server_certs = false) {
-	global $a_cert;
 	$openvpn_compatible_certs = cert_build_list('cert', 'OpenVPN');
 
 	if ($include_none) {
@@ -315,13 +313,14 @@ function openvpn_build_cert_list($include_none = false, $prioritize_server_certs
 		$non_server_list['  '] = gettext("===== Non-Server Certificates =====");
 	}
 
-	foreach ($a_cert as $cert) {
+	foreach (config_get_path('cert', []) as $cert) {
 		if (!array_key_exists($cert['refid'], $openvpn_compatible_certs)) {
 			continue;
 		}
 		$properties = array();
 		$propstr = "";
 		$ca = lookup_ca($cert['caref']);
+		$ca = $ca['item'];
 		$purpose = cert_get_purpose($cert['crt'], true);
 
 		if ($purpose['server'] == "Yes") {
@@ -1121,6 +1120,7 @@ function openvpn_reconfigure($mode, $settings) {
 				$cert = "";
 			} else {
 				$cert = lookup_cert($settings['certref']);
+				$cert = $cert['item'];
 				/* XXX: Seems not used at all! */
 				$servercn = urlencode(cert_get_cn($cert['crt']));
 				$conf .= "tls-verify \"/usr/local/sbin/ovpn_auth_verify tls '{$servercn}' {$settings['cert_depth']}\"\n";
@@ -1315,8 +1315,9 @@ function openvpn_reconfigure($mode, $settings) {
 			@unlink_if_exists("{$capath}/*.r*");
 			/* Find the CRL listed in the settings */
 			if (!empty($settings['crlref'])) {
-				$crl = lookup_crl($settings['crlref']);
-				crl_update($crl);
+				$crl_item_config = lookup_crl($settings['crlref']);
+				$crl = &$crl_item_config['item'];
+				crl_update($crl_item_config);
 			}
 			/* For each CA in the chain, setup the CApath */
 			foreach ($cas as $ca) {
@@ -1327,6 +1328,7 @@ function openvpn_reconfigure($mode, $settings) {
 
 			if (!empty($settings['certref'])) {
 				$cert = lookup_cert($settings['certref']);
+				$cert = $cert['item'];
 				openvpn_add_keyfile($cert['crt'], $conf, $mode_id, "cert");
 				openvpn_add_keyfile($cert['prv'], $conf, $mode_id, "key");
 			}
@@ -2199,8 +2201,9 @@ function openvpn_refresh_crls() {
 			$cas = ca_chain_array($param);
 			$capath = "{$g['openvpn_base']}/server{$settings['vpnid']}/ca";
 			if (!empty($settings['crlref'])) {
-				$crl = lookup_crl($settings['crlref']);
-				crl_update($crl);
+				$crl_item_config = lookup_crl($settings['crlref']);
+				$crl = &$crl_item_config['item'];
+				crl_update($crl_item_config);
 			}
 			foreach ($cas as $ca) {
 				ca_setup_capath($ca, $capath, $crl, true);
diff --git a/src/etc/inc/openvpn.tls-verify.php b/src/etc/inc/openvpn.tls-verify.php
index 3ce056d462..0a615c15aa 100644
--- a/src/etc/inc/openvpn.tls-verify.php
+++ b/src/etc/inc/openvpn.tls-verify.php
@@ -77,6 +77,7 @@ foreach (config_get_path('openvpn/openvpn-server', []) as $ovpns) {
 	if (($ovpns['vpnid'] == $current_vpnid['1']) && ($ovpns['ocspcheck'] == 'yes')) {
 		$capath = "/var/etc/openvpn/server{$ovpns['vpnid']}/ca/";
 		$ca = lookup_ca($ovpns['caref']);
+		$ca = $ca['item'];
 		$cert_contents = base64_decode($ca['crt']);
 		$cert_details = openssl_x509_parse($cert_contents);
 		$issuer = $capath . $cert_details['hash'] . ".0";
diff --git a/src/etc/inc/system.inc b/src/etc/inc/system.inc
index e2a0dd2627..fcf6b18d23 100644
--- a/src/etc/inc/system.inc
+++ b/src/etc/inc/system.inc
@@ -1646,6 +1646,7 @@ function system_webgui_start() {
 	if (config_get_path('system/webgui/protocol') == "https") {
 		// Ensure that we have a webConfigurator CERT
 		$cert = lookup_cert(config_get_path('system/webgui/ssl-certref'));
+		$cert = $cert['item'];
 		if (!is_array($cert) || !$cert['crt'] || !$cert['prv'] ||
 		    cert_chain_has_weak_digest($cert)) {
 			$cert = cert_create_selfsigned();
@@ -1898,6 +1899,7 @@ EOD;
 		$nginx_config .= "\t\tssl_session_tickets off;\n";
 		$nginx_config .= "\t\tssl_dhparam /etc/dh-parameters.4096;\n";
 		$cert_temp = lookup_cert(config_get_path('system/webgui/ssl-certref'));
+		$cert_temp = $cert_temp['item'];
 		if ((config_get_path('system/webgui/ocsp-staple') == true) or
 		    (cert_get_ocspstaple($cert_temp['crt']) == true)) {
 			$nginx_config .= "\t\tssl_stapling on;\n";
diff --git a/src/etc/inc/unbound.inc b/src/etc/inc/unbound.inc
index 2575f25c9a..7cff2429f3 100644
--- a/src/etc/inc/unbound.inc
+++ b/src/etc/inc/unbound.inc
@@ -302,6 +302,7 @@ EOF;
 
 		// Lookup CA and Server Cert
 		$cert = lookup_cert($unboundcfg['sslcertref']);
+		$cert = $cert['item'];
 		$ca = ca_chain($cert);
 		$cert_chain = base64_decode($cert['crt']);
 		if (!empty($ca)) {
diff --git a/src/etc/inc/upgrade_config.inc b/src/etc/inc/upgrade_config.inc
index b1eb9e197c..38b55c0a71 100644
--- a/src/etc/inc/upgrade_config.inc
+++ b/src/etc/inc/upgrade_config.inc
@@ -2338,7 +2338,8 @@ function upgrade_059_to_060() {
 			$subject = cert_get_subject($ca['crt']);
 			$issuer = cert_get_issuer($ca['crt']);
 			if ($issuer <> $subject) {
-				$issuer_crt =& lookup_ca_by_subject($issuer);
+				$issuer_crt = lookup_ca_by_subject($issuer);
+				$issuer_crt = $issuer_crt['item'];
 				if ($issuer_crt) {
 					$ca['caref'] = $issuer_crt['refid'];
 				}
@@ -2351,7 +2352,8 @@ function upgrade_059_to_060() {
 				$subject = cert_get_subject($cert['crt']);
 				$issuer = cert_get_issuer($cert['crt']);
 				if ($issuer <> $subject) {
-					$issuer_crt =& lookup_ca_by_subject($issuer);
+					$issuer_crt = lookup_ca_by_subject($issuer);
+					$issuer_crt = $issuer_crt['item'];
 					if ($issuer_crt) {
 						$cert['caref'] = $issuer_crt['refid'];
 					}
@@ -2599,7 +2601,6 @@ function upgrade_068_to_069() {
 		return;
 	}
 
-	$cert_config = config_get_path('cert');
 	foreach ($user_config as & $user) {
 		if (!is_array($user['cert'])) {
 			continue;
@@ -2616,14 +2617,13 @@ function upgrade_068_to_069() {
 			}
 			// Keep the cert references for this user
 			$rids[] = $tcert['refid'];
-			$cert_config[] = $tcert;
+			config_set_path('cert/', $tcert);
 		}
 		// Replace user certs with cert references instead.
 		if (count($rids) > 0) {
 			$user['cert'] = $rids;
 		}
 	}
-	config_set_path('cert', $cert_config);
 	config_set_path('system/user', $user_config);
 }
 
@@ -6947,6 +6947,7 @@ function upgrade_230_to_231() {
 			/* If using SSL/TLS, check if (server|client) certificate is weak, if so, disable tunnel */
 			if (!empty($settings['certref'])) {
 				$cert = lookup_cert($settings['certref']);
+				$cert = $cert['item'];
 				/* Disable only if weak and not already disabled */
 				if (cert_has_weak_digest($cert['crt']) &&
 					!isset($settings['disable'])) {
@@ -6987,6 +6988,7 @@ function upgrade_231_to_232() {
 	if (config_get_path('system/webgui/protocol') == "https" &&
 	    !empty(config_get_path('system/webgui/ssl-certref'))) {
 		$cert = lookup_cert(config_get_path('system/webgui/ssl-certref'));
+		$cert = $cert['item'];
 		/* If the GUI certificate is invalid or weak, replace it */
 		if (!is_array($cert) || !$cert['crt'] || !$cert['prv'] ||
 		    cert_chain_has_weak_digest($cert)) {
@@ -7008,6 +7010,7 @@ function upgrade_231_to_232() {
 		}
 
 		$cert = lookup_cert($portal['certref']);
+		$cert = $cert['item'];
 
 		/* If the cert is invalid or weak, generate a new self-signed
 		 * cert using configured HTTPS server name, if present */
diff --git a/src/usr/local/pfSense/include/www/system_advanced_admin.inc b/src/usr/local/pfSense/include/www/system_advanced_admin.inc
index 04638d0054..3786d2e382 100644
--- a/src/usr/local/pfSense/include/www/system_advanced_admin.inc
+++ b/src/usr/local/pfSense/include/www/system_advanced_admin.inc
@@ -61,8 +61,7 @@ function getAdvancedAdminConfig($json = false) {
 	$pconfig['sshguard_detection_time'] = config_get_path('system/sshguard_detection_time', '');
 	$pconfig['sshguard_whitelist'] = config_get_path('system/sshguard_whitelist', '');
 	$pconfig['interfaces_lan'] = config_get_path('interfaces/lan');
-	$a_cert = config_get_path('cert', []);
-	$pconfig['certsavailable'] = (is_array($a_cert) && count($a_cert));
+	$pconfig['certsavailable'] = count(config_get_path('cert', [])) > 0;
 	if (!$pconfig['webguiproto'] || !$pconfig['certsavailable']) {
 		$pconfig['webguiproto'] = 'http';
 	}
diff --git a/src/usr/local/www/services_captiveportal.php b/src/usr/local/www/services_captiveportal.php
index b5513b05c7..532987b21d 100644
--- a/src/usr/local/www/services_captiveportal.php
+++ b/src/usr/local/www/services_captiveportal.php
@@ -105,9 +105,6 @@ switch ($action) {
 		/* Do nothing, no match */
 }
 
-$a_ca = config_get_path('ca', []);
-$a_cert = config_get_path('cert', []);
-
 $cpzoneid = $pconfig['zoneid'] = config_get_path("captiveportal/{$cpzone}/zoneid");
 $pconfig['descr'] = config_get_path("captiveportal/{$cpzone}/descr");
 $pconfig['cinterface'] = config_get_path("captiveportal/{$cpzone}/interface");
diff --git a/src/usr/local/www/system_advanced_admin.php b/src/usr/local/www/system_advanced_admin.php
index edd9e4c6e6..eb071c99eb 100644
--- a/src/usr/local/www/system_advanced_admin.php
+++ b/src/usr/local/www/system_advanced_admin.php
@@ -426,6 +426,7 @@ events.push(function() {
 	hideCheckbox('webgui-hsts', $('input[name=webguiproto]:checked').val() == 'http');
 	hideCheckbox('ocsp-staple', "<?php 
 			$cert_temp = lookup_cert($pconfig['ssl-certref']);
+			$cert_temp = $cert_temp['item'];
 			echo (cert_get_ocspstaple($cert_temp['crt']) ? "true" : "false");
 			?>" === "true");
 
diff --git a/src/usr/local/www/system_authservers.php b/src/usr/local/www/system_authservers.php
index 8db32689f9..257665e2aa 100644
--- a/src/usr/local/www/system_authservers.php
+++ b/src/usr/local/www/system_authservers.php
@@ -107,8 +107,7 @@ if (!is_array($config['system']['authserver'])) {
 
 $a_server = array_values(auth_get_authserver_list());
 
-init_config_arr(array('ca'));
-$a_ca = &$config['ca'];
+config_init_path('ca');
 
 $act = $_REQUEST['act'];
 
@@ -600,7 +599,7 @@ $section->addInput(new Form_Select(
 ));
 
 $ldapCaRef = array('global' => 'Global Root CA List');
-foreach ($a_ca as $ca) {
+foreach (config_get_path('ca', []) as $ca) {
 	$ldapCaRef[$ca['refid']] = $ca['descr'];
 }
 
@@ -924,7 +923,7 @@ events.push(function() {
 		var authserver = $('#authmode').val();
 		var cert;
 
-<?php if (count($a_ca) > 0): ?>
+<?php if (count(config_get_path('ca', [])) > 0): ?>
 			cert = $('#ldap_caref').val();
 <?php else: ?>
 			cert = '';
diff --git a/src/usr/local/www/system_camanager.php b/src/usr/local/www/system_camanager.php
index e722c0baff..db24a52af0 100644
--- a/src/usr/local/www/system_camanager.php
+++ b/src/usr/local/www/system_camanager.php
@@ -47,14 +47,9 @@ $default_lifetime = min(3650, $max_lifetime);
 $openssl_ecnames = cert_build_curve_list();
 $class = "success";
 
-init_config_arr(array('ca'));
-$a_ca = &$config['ca'];
-
-init_config_arr(array('cert'));
-$a_cert = &$config['cert'];
-
-init_config_arr(array('crl'));
-$a_crl = &$config['crl'];
+config_init_path('ca');
+config_init_path('cert');
+config_init_path('crl');
 
 $act = $_REQUEST['act'];
 
@@ -62,7 +57,8 @@ if (isset($_REQUEST['id']) && ctype_alnum($_REQUEST['id'])) {
 	$id = $_REQUEST['id'];
 }
 if (!empty($id)) {
-	$thisca =& lookup_ca($id);
+	$ca_item_config = lookup_ca($id);
+	$thisca = &$ca_item_config['item'];
 }
 
 /* Actions other than 'new' require an ID.
@@ -83,21 +79,21 @@ switch ($act) {
 			$class = "danger";
 		} else {
 			/* Only remove CA reference when deleting. It can be reconnected if a new matching CA is imported */
-			foreach ($a_cert as $cid => $acrt) {
+			foreach (config_get_path('cert', []) as $cid => $acrt) {
 				if ($acrt['caref'] == $thisca['refid']) {
-					unset($a_cert[$cid]['caref']);
+					config_del_path("cert/{$cid}/caref");
 				}
 			}
 			/* Remove any CRLs for this CA, there is no way to recover the connection once the CA has been removed. */
-			foreach ($a_crl as $cid => $acrl) {
+			foreach (config_get_path('crl', []) as $cid => $acrl) {
 				if ($acrl['caref'] == $thisca['refid']) {
-					unset($a_crl[$cid]);
+					config_del_path("crl/{$cid}");
 				}
 			}
 			/* Delete the CA */
-			foreach ($a_ca as $cid => $aca) {
+			foreach (config_get_path('ca', []) as $cid => $aca) {
 				if ($aca['refid'] == $thisca['refid']) {
-					unset($a_ca[$cid]);
+					config_del_path("ca/{$cid}");
 				}
 			}
 			$savemsg = sprintf(gettext("Deleted Certificate Authority %s and associated CRLs"), htmlspecialchars($name));
@@ -332,9 +328,9 @@ if ($_POST['save']) {
 		}
 
 		if (isset($id) && $thisca) {
-			$thisca = $ca;
+			config_set_path("ca/{$ca_item_config['item']}", $ca);
 		} else {
-			$a_ca[] = $ca;
+			config_set_path('ca/', $ca);
 		}
 
 		if (!$input_errors) {
@@ -428,7 +424,7 @@ $pluginparams['type'] = 'certificates';
 $pluginparams['event'] = 'used_ca';
 $certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
 
-foreach ($a_ca as $ca):
+foreach (config_get_path('ca', []) as $ca):
 	$name = htmlspecialchars($ca['descr']);
 	$subj = cert_get_subject($ca['crt']);
 	$issuer = cert_get_issuer($ca['crt']);
@@ -442,17 +438,18 @@ foreach ($a_ca as $ca):
 	$certcount = 0;
 
 	$issuer_ca = lookup_ca($ca['caref']);
+	$issuer_ca = $issuer_ca['item'];
 	if ($issuer_ca) {
 		$issuer_name = htmlspecialchars($issuer_ca['descr']);
 	}
 
-	foreach ($a_cert as $cert) {
+	foreach (config_get_path('cert', []) as $cert) {
 		if ($cert['caref'] == $ca['refid']) {
 			$certcount++;
 		}
 	}
 
-	foreach ($a_ca as $cert) {
+	foreach (config_get_path('ca', []) as $cert) {
 		if ($cert['caref'] == $ca['refid']) {
 			$certcount++;
 		}
@@ -661,7 +658,7 @@ $section = new Form_Section('Internal Certificate Authority');
 $section->addClass('toggle-internal', 'toggle-intermediate', 'collapse');
 
 $allCas = array();
-foreach ($a_ca as $ca) {
+foreach (config_get_path('ca', []) as $ca) {
 	if (!$ca['prv']) {
 			continue;
 	}
@@ -782,7 +779,7 @@ $form->add($section);
 print $form;
 
 $internal_ca_count = 0;
-foreach ($a_ca as $ca) {
+foreach (config_get_path('ca', []) as $ca) {
 	if ($ca['prv']) {
 		$internal_ca_count++;
 	}
diff --git a/src/usr/local/www/system_certmanager.php b/src/usr/local/www/system_certmanager.php
index 72d323e6ca..bf2933b263 100644
--- a/src/usr/local/www/system_certmanager.php
+++ b/src/usr/local/www/system_certmanager.php
@@ -65,14 +65,11 @@ if (isset($userid)) {
 	config_init_path('system/user');
 }
 
-init_config_arr(array('ca'));
-$a_ca = &$config['ca'];
-
-init_config_arr(array('cert'));
-$a_cert = &$config['cert'];
+config_init_path('ca');
+config_init_path('cert');
 
 $internal_ca_count = 0;
-foreach ($a_ca as $ca) {
+foreach (config_get_path('cert', []) as $ca) {
 	if ($ca['prv']) {
 		$internal_ca_count++;
 	}
@@ -96,7 +93,8 @@ if (isset($_REQUEST['id']) && ctype_alnum($_REQUEST['id'])) {
 	$id = $_REQUEST['id'];
 }
 if (!empty($id)) {
-	$thiscert =& lookup_cert($id);
+	$cert_item_config = lookup_cert($id);
+	$thiscert = &$cert_item_config['item'];
 }
 
 /* Actions other than 'new' require an ID.
@@ -116,9 +114,9 @@ switch ($act) {
 			$savemsg = sprintf(gettext("Certificate %s is in use and cannot be deleted"), $name);
 			$class = "danger";
 		} else {
-			foreach ($a_cert as $cid => $acrt) {
+			foreach (config_get_path('cert', []) as $cid => $acrt) {
 				if ($acrt['refid'] == $thiscert['refid']) {
-					unset($a_cert[$cid]);
+					config_del_path("cert/{$cid}");
 				}
 			}
 			$savemsg = sprintf(gettext("Deleted certificate %s"), $name);
@@ -462,8 +460,10 @@ if ($_POST['save'] == gettext("Save")) {
 			case 'sign':
 				/* Sign a CSR */
 				$csrid = lookup_cert($pconfig['csrtosign']);
-				$ca = & lookup_ca($pconfig['catosignwith']);
-				// Read the CSR from $config, or if a new one, from the textarea
+				$csrid = $csrid['item'];
+				$ca_item_config = lookup_ca($pconfig['catosignwith']);
+				$ca = &$ca_item_config['item'];
+				// Read the CSR from config array, or if a new one, from the textarea
 				if ($pconfig['csrtosign'] === "new") {
 					$csr = $pconfig['csrpaste'];
 				} else {
@@ -476,6 +476,7 @@ if ($_POST['save'] == gettext("Save")) {
 					$altname_str = implode(",", $altnames_tmp);
 				}
 				$n509 = csr_sign($csr, $ca, $pconfig['csrsign_lifetime'], $pconfig['type'], $altname_str, $pconfig['csrsign_digest_alg']);
+				config_set_path("ca/{$ca_item_config['idx']}", $ca);
 				if ($n509) {
 					// Gather the details required to save the new cert
 					$newcert = array();
@@ -490,7 +491,7 @@ if ($_POST['save'] == gettext("Save")) {
 						$newcert['prv'] = $csrid['prv'];
 					}
 					// Add it to the config file
-					$config['cert'][] = $newcert;
+					config_set_path('cert/', $newcert);
 					$savemsg = sprintf(gettext("Signed certificate %s"), htmlspecialchars($newcert['descr']));
 					unset($act);
 				}
@@ -513,7 +514,7 @@ if ($_POST['save'] == gettext("Save")) {
 							$cn = $int_data['subject']['CN'];
 							$int_ca = array('descr' => $cn, 'refid' => uniqid());
 							if (ca_import($int_ca, $intermediate)) {
-								$a_ca[] = $int_ca;
+								config_set_path('ca/', $int_ca);
 							}
 						}
 					}
@@ -619,8 +620,9 @@ if ($_POST['save'] == gettext("Save")) {
 
 		if (isset($id) && $thiscert) {
 			$thiscert = $cert;
+			config_set_path("cert/{$cert_item_config['idx']}", $thiscert);
 		} elseif ($cert) {
-			$a_cert[] = $cert;
+			config_set_path('cert/', $cert);
 		}
 
 		if (isset($userid) && (config_get_path('system/user') !== null)) {
@@ -668,6 +670,7 @@ if ($_POST['save'] == gettext("Save")) {
 		$cert['descr'] = $pconfig['descr'];
 		csr_complete($cert, $pconfig['cert']);
 		$thiscert = $cert;
+		config_set_path("cert/{$cert_item_config['idx']}", $thiscert);
 		$savemsg = sprintf(gettext("Updated certificate signing request %s"), htmlspecialchars($pconfig['descr']));
 		write_config($savemsg);
 		pfSenseHeader("system_certmanager.php");
@@ -771,10 +774,9 @@ if (in_array($act, array('new', 'edit')) || (($_POST['save'] == gettext("Save"))
 
 	// Return an array containing the IDs od all CAs
 	function list_cas() {
-		global $a_ca;
 		$allCas = array();
 
-		foreach ($a_ca as $ca) {
+		foreach (config_get_path('ca', []) as $ca) {
 			if ($ca['prv']) {
 				$allCas[$ca['refid']] = $ca['descr'];
 			}
@@ -938,7 +940,7 @@ if (in_array($act, array('new', 'edit')) || (($_POST['save'] == gettext("Save"))
 		));
 	} else {
 		$allCas = array();
-		foreach ($a_ca as $ca) {
+		foreach (config_get_path('ca', []) as $ca) {
 			if (!$ca['prv']) {
 				continue;
 			}
@@ -1165,6 +1167,7 @@ if (in_array($act, array('new', 'edit')) || (($_POST['save'] == gettext("Save"))
 		}
 
 		$ca = lookup_ca($cert['caref']);
+		$ca = $ca['item'];
 		if ($ca) {
 			$cert['descr'] .= " (CA: {$ca['descr']})";
 		}
@@ -1402,7 +1405,7 @@ $pluginparams = array();
 $pluginparams['type'] = 'certificates';
 $pluginparams['event'] = 'used_certificates';
 $certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
-foreach ($a_cert as $cert):
+foreach (config_get_path('cert', []) as $cert):
 	if (!is_array($cert) || empty($cert)) {
 		continue;
 	}
@@ -1434,6 +1437,7 @@ foreach ($a_cert as $cert):
 	}
 
 	$ca = lookup_ca($cert['caref']);
+	$ca = $ca['item'];
 	if ($ca) {
 		$caname = htmlspecialchars($ca['descr']);
 	}
@@ -1616,7 +1620,7 @@ events.push(function() {
 
 		switch (caref) {
 <?php
-			foreach ($a_ca as $ca):
+			foreach (config_get_path('ca', []) as $ca):
 				if (!$ca['prv']) {
 					continue;
 				}
diff --git a/src/usr/local/www/system_certmanager_renew.php b/src/usr/local/www/system_certmanager_renew.php
index 46b5c8a548..d95026c1cf 100644
--- a/src/usr/local/www/system_certmanager_renew.php
+++ b/src/usr/local/www/system_certmanager_renew.php
@@ -35,23 +35,30 @@ require_once("pfsense-utils.inc");
 
 global $cert_strict_values, $curve_compatible_list;
 
-init_config_arr(array('ca'));
-$a_ca = &$config['ca'];
-
-init_config_arr(array('cert'));
-$a_cert = &$config['cert'];
+config_init_path('ca');
+config_init_path('cert');
 
 $type = $_REQUEST['type'];
 
 switch ($type) {
 	case 'ca':
-		$torenew = & lookup_ca($_REQUEST['refid']);
+		$ca_item_config = lookup_ca($_REQUEST['refid']);
+		$torenew = &$ca_item_config['item'];
+		$torenew_config = [
+			'path' => "ca/{$ca_item_config['idx']}",
+			'item' => &$torenew
+		];
 		$returnpage = "system_camanager.php";
 		$service_function = 'ca_get_all_services';
 		$typestring = gettext("Certificate Authority");
 		break;
 	case 'cert':
-		$torenew = & lookup_cert($_REQUEST['refid']);
+		$cert_item_config = lookup_cert($_REQUEST['refid']);
+		$torenew = &$cert_item_config['item'];
+		$torenew_config = [
+			'path' => "cert/{$cert_item_config['idx']}",
+			'item' => &$torenew
+		];
 		$returnpage = "system_certmanager.php";
 		$service_function = 'cert_get_all_services';
 		$typestring = gettext("Certificate");
@@ -69,7 +76,7 @@ $old_serial = cert_get_serial($torenew['crt']);
 if ($_POST['renew']) {
 	$input_errors = array();
 	$old_serial = cert_get_serial($torenew['crt']);
-	if (cert_renew($torenew, ($_POST['reusekey'] == "yes"), ($_POST['strictsecurity'] == "yes"), ($_POST['reuseserial'] == "yes"))) {
+	if (cert_renew($torenew_config, ($_POST['reusekey'] == "yes"), ($_POST['strictsecurity'] == "yes"), ($_POST['reuseserial'] == "yes"))) {
 		$new_serial = cert_get_serial($torenew['crt']);
 		$message = sprintf(gettext("Renewed %s %s (%s) - Serial %s -> %s"),
 					$typestring,
@@ -108,7 +115,8 @@ $cert_details = openssl_x509_parse(base64_decode($torenew['crt']));
 $subj = cert_get_subject($torenew['crt']);
 $issuer = cert_get_issuer($torenew['crt']);
 if (!empty($torenew['caref'])) {
-	$issuer_ca = & lookup_ca($torenew['caref']);
+	$issuer_ca = lookup_ca($torenew['caref']);
+	$issuer_ca = $issuer_ca['item'];
 	if ($issuer_ca && !empty($issuer_ca['descr'])) {
 		$issuer = "{$issuer_ca['descr']}: {$issuer}";
 	}
diff --git a/src/usr/local/www/system_crlmanager.php b/src/usr/local/www/system_crlmanager.php
index 80c99e0530..c157507a80 100644
--- a/src/usr/local/www/system_crlmanager.php
+++ b/src/usr/local/www/system_crlmanager.php
@@ -47,19 +47,14 @@ if (isset($_REQUEST['id']) && ctype_alnum($_REQUEST['id'])) {
 	$id = $_REQUEST['id'];
 }
 
-init_config_arr(array('ca'));
-$a_ca = &$config['ca'];
-
-init_config_arr(array('cert'));
-$a_cert = &$config['cert'];
-
-init_config_arr(array('crl'));
-$a_crl = &$config['crl'];
+config_init_path('ca');
+config_init_path('cert');
+config_init_path('crl');
 
 /* Clean up blank entries missing a reference ID */
-foreach ($a_crl as $cid => $acrl) {
+foreach (config_get_path('crl', []) as $cid => $acrl) {
 	if (!isset($acrl['refid'])) {
-		unset ($a_crl[$cid]);
+		config_del_path("crl/{$cid}");
 	}
 }
 
@@ -68,7 +63,8 @@ $act = $_REQUEST['act'];
 $cacert_list = array();
 
 if (!empty($id)) {
-	$thiscrl =& lookup_crl($id);
+	$crl_item_config = lookup_crl($id);
+	$thiscrl = &$crl_item_config['item'];
 }
 
 /* Actions other than 'new' require a CRL to act upon.
@@ -90,9 +86,9 @@ switch ($act) {
 			$savemsg = sprintf(gettext("Certificate Revocation List %s is in use and cannot be deleted."), $name);
 			$class = "danger";
 		} else {
-			foreach ($a_crl as $cid => $acrl) {
+			foreach (config_get_path('crl', []) as $cid => $acrl) {
 				if ($acrl['refid'] == $thiscrl['refid']) {
-					unset($a_crl[$cid]);
+					config_del_path("crl/{$cid}");
 				}
 			}
 			write_config("Deleted CRL {$name}.");
@@ -105,7 +101,8 @@ switch ($act) {
 		$pconfig['caref'] = $_REQUEST['caref'];
 		$pconfig['lifetime'] = $default_lifetime;
 		$pconfig['serial'] = "0";
-		$crlca =& lookup_ca($pconfig['caref']);
+		$crlca = lookup_ca($pconfig['caref']);
+		$crlca = $crlca['item'];
 		if (!$crlca) {
 			$input_errors[] = gettext('Invalid CA');
 			unset($act);
@@ -138,7 +135,8 @@ switch ($act) {
 			pfSenseHeader("system_crlmanager.php");
 			exit;
 		}
-		$crl =& lookup_crl($pconfig['crlref']);
+		$crl_item_config = lookup_crl($pconfig['crlref']);
+		$crl = &$crl_item_config['item'];
 
 		if (!is_array($pconfig['certref'])) {
 			$pconfig['certref'] = array();
@@ -161,6 +159,7 @@ switch ($act) {
 		}
 		foreach ($pconfig['certref'] as $rcert) {
 			$cert = lookup_cert($rcert);
+			$cert = $cert['item'];
 			if ($crl['caref'] == $cert['caref']) {
 				$revoke_list[] = $cert;
 			} else {
@@ -176,7 +175,7 @@ switch ($act) {
 				$savemsg = "Revoked certificate(s) in CRL {$crl['descr']}.";
 				$reason = (empty($pconfig['crlreason'])) ? 0 : $pconfig['crlreason'];
 				foreach ($revoke_list as $cert) {
-					cert_revoke($cert, $crl, $reason);
+					cert_revoke($cert, $crl_item_config, $reason);
 				}
 				// refresh IPsec and OpenVPN CRLs
 				openvpn_refresh_crls();
@@ -209,7 +208,7 @@ switch ($act) {
 		}
 		$certname = htmlspecialchars($thiscert['descr']);
 		$crlname = htmlspecialchars($thiscrl['descr']);
-		if (cert_unrevoke($thiscert, $thiscrl)) {
+		if (cert_unrevoke($thiscert, $crl_item_config)) {
 			$savemsg = sprintf(gettext('Deleted Certificate %1$s from CRL %2$s.'), $certname, $crlname);
 			$class = "success";
 			// refresh IPsec and OpenVPN CRLs
@@ -224,7 +223,7 @@ switch ($act) {
 		break;
 	case 'exp':
 		/* Exporting the CRL contents*/
-		crl_update($thiscrl);
+		crl_update($crl_item_config);
 		send_user_download('data', base64_decode($thiscrl['text']), "{$thiscrl['descr']}.crl");
 		break;
 	default:
@@ -291,7 +290,9 @@ if ($_POST['save'] && empty($input_errors)) {
 		}
 
 		if (!$thiscrl) {
-			$a_crl[] = $crl;
+			config_set_path('crl/', $crl);
+		} else {
+			config_set_path("crl/{$crl_item_config['idx']}", $crl);
 		}
 
 		write_config("Saved CRL {$crl['descr']}");
@@ -353,11 +354,9 @@ function build_method_list($importonly = false) {
 }
 
 function build_ca_list() {
-	global $a_ca;
-
 	$list = array();
 
-	foreach ($a_ca as $ca) {
+	foreach (config_get_path('ca', []) as $ca) {
 		$list[$ca['refid']] = $ca['descr'];
 	}
 
@@ -365,10 +364,10 @@ function build_ca_list() {
 }
 
 function build_cacert_list() {
-	global $a_cert, $crl, $id;
+	global $crl, $id;
 
 	$list = array();
-	foreach ($a_cert as $cert) {
+	foreach (config_get_path('cert', []) as $cert) {
 		if ((isset($cert['caref']) && !empty($cert['caref'])) &&
 		    ($cert['caref'] == $crl['caref']) &&
 		    !is_cert_revoked($cert, $id)) {
@@ -676,16 +675,17 @@ if ($act == "new" || $act == gettext("Save")) {
 	$certificates_used_by_packages = pkg_call_plugins('plugin_certificates', $pluginparams);
 	// Map CRLs to CAs in one pass
 	$ca_crl_map = array();
-	foreach ($a_crl as $crl) {
+	foreach (config_get_path('crl', []) as $crl) {
 		$ca_crl_map[$crl['caref']][] = $crl['refid'];
 	}
 
 	$i = 0;
-	foreach ($a_ca as $ca):
+	foreach (config_get_path('ca', []) as $ca):
 		$caname = htmlspecialchars($ca['descr']);
 		if (is_array($ca_crl_map[$ca['refid']])):
 			foreach ($ca_crl_map[$ca['refid']] as $crl):
 				$tmpcrl = lookup_crl($crl);
+				$tmpcrl = $tmpcrl['item'];
 				$internal = is_crl_internal($tmpcrl);
 				if ($internal && (!isset($tmpcrl['cert']) || empty($tmpcrl['cert'])) ) {
 					$tmpcrl['cert'] = array();
diff --git a/src/usr/local/www/system_usermanager.php b/src/usr/local/www/system_usermanager.php
index 27c505403e..5c8f594473 100644
--- a/src/usr/local/www/system_usermanager.php
+++ b/src/usr/local/www/system_usermanager.php
@@ -303,6 +303,7 @@ if ($_POST['save'] && !$read_only) {
 
 	if (!empty($_POST['name'])) {
 		$ca = lookup_ca($_POST['caref']);
+		$ca = $ca['item'];
 		if (!$ca) {
 			$input_errors[] = gettext("Invalid internal Certificate Authority") . "\n";
 		}
@@ -610,7 +611,9 @@ function build_cert_table() {
 	$i = 0;
 	foreach (config_get_path("system/user/{$id}/cert", []) as $certref) {
 		$cert = lookup_cert($certref);
+		$cert = $cert['item'];
 		$ca = lookup_ca($cert['caref']);
+		$ca = $ca['item'];
 		$revokedstr =	is_cert_revoked($cert) ? '<b> Revoked</b>':'';
 
 		$certhtml .=	'<tr>';
diff --git a/src/usr/local/www/vpn_ipsec_phase1.php b/src/usr/local/www/vpn_ipsec_phase1.php
index 5d02b89a51..449d3ca8f4 100644
--- a/src/usr/local/www/vpn_ipsec_phase1.php
+++ b/src/usr/local/www/vpn_ipsec_phase1.php
@@ -524,7 +524,8 @@ if ($_POST['save']) {
 	}
 
 	if (!empty($pconfig['certref'])) {
-		$errchkcert =& lookup_cert($pconfig['certref']);
+		$errchkcert = lookup_cert($pconfig['certref']);
+		$errchkcert = $errchkcert['item'];
 		if (is_array($errchkcert)) {
 			if (!cert_check_pkey_compatibility($errchkcert['prv'], 'IPsec')) {
 				$input_errors[] = gettext("The selected ECDSA certificate does not use a curve compatible with IKEv2");
diff --git a/src/usr/local/www/vpn_openvpn_client.php b/src/usr/local/www/vpn_openvpn_client.php
index 72c84ff21d..539f8564f2 100644
--- a/src/usr/local/www/vpn_openvpn_client.php
+++ b/src/usr/local/www/vpn_openvpn_client.php
@@ -40,14 +40,9 @@ global $openvpn_sharedkey_warning;
 init_config_arr(array('openvpn', 'openvpn-client'));
 $a_client = &$config['openvpn']['openvpn-client'];
 
-init_config_arr(array('ca'));
-$a_ca = &$config['ca'];
-
-init_config_arr(array('cert'));
-$a_cert = &$config['cert'];
-
-init_config_arr(array('crl'));
-$a_crl = &$config['crl'];
+config_init_path('ca');
+config_init_path('cert');
+config_init_path('crl');
 
 $proxy_auth_types = array('none' => gettext('none'), 'basic' => gettext('basic'), 'ntlm' => gettext('ntlm'));
 $certlist = openvpn_build_cert_list(true);
@@ -881,7 +876,7 @@ if ($act=="new" || $act=="edit"):
 			'For example, if the server is set to 0, the client must be set to 1. ' .
 			'Both may be set to omit the direction, in which case the TLS Key will be used bidirectionally.');
 
-	if (count($a_ca)) {
+	if (count(config_get_path('ca', []))) {
 		$section->addInput(new Form_Select(
 			'caref',
 			'*Peer Certificate Authority',
@@ -895,7 +890,7 @@ if ($act=="new" || $act=="edit"):
 		));
 	}
 
-	if (count($a_crl)) {
+	if (count(config_get_path('crl', []))) {
 		$section->addInput(new Form_Select(
 			'crlref',
 			'Peer Certificate Revocation list',
diff --git a/src/usr/local/www/vpn_openvpn_server.php b/src/usr/local/www/vpn_openvpn_server.php
index 41db07aad7..851d5b0dee 100644
--- a/src/usr/local/www/vpn_openvpn_server.php
+++ b/src/usr/local/www/vpn_openvpn_server.php
@@ -40,18 +40,13 @@ global $openvpn_sharedkey_warning;
 init_config_arr(array('openvpn', 'openvpn-server'));
 $a_server = &$config['openvpn']['openvpn-server'];
 
-init_config_arr(array('ca'));
-$a_ca = &$config['ca'];
+config_init_path('ca');
+config_init_path('cert');
+config_init_path('crl');
 
-init_config_arr(array('cert'));
-$a_cert = &$config['cert'];
-
-init_config_arr(array('crl'));
-$a_crl = &$config['crl'];
-
-foreach ($a_crl as $cid => $acrl) {
+foreach (config_get_path('crl', []) as $cid => $acrl) {
 	if (!isset($acrl['refid'])) {
-		unset ($a_crl[$cid]);
+		config_del_path("crl/{$cid}");
 	}
 }
 
@@ -1069,7 +1064,7 @@ if ($act=="new" || $act=="edit"):
 			'For example, if the server is set to 0, the client must be set to 1. ' .
 			'Both may be set to omit the direction, in which case the TLS Key will be used bidirectionally.');
 
-	if (count($a_ca)) {
+	if (count(config_get_path('ca', []))) {
 		$section->addInput(new Form_Select(
 			'caref',
 			'*Peer Certificate Authority',
@@ -1083,7 +1078,7 @@ if ($act=="new" || $act=="edit"):
 		));
 	}
 
-	if (count($a_crl)) {
+	if (count(config_get_path('crl', []))) {
 		$section->addInput(new Form_Select(
 			'crlref',
 			'Peer Certificate Revocation list',
@@ -1112,9 +1107,10 @@ if ($act=="new" || $act=="edit"):
 	));
 
 	$certhelp = '<span id="certtype"></span>';
-	if (count($a_cert)) {
+	if (count(config_get_path('cert', []))) {
 		if (!empty(trim($pconfig['certref']))) {
 			$thiscert = lookup_cert($pconfig['certref']);
+			$thiscert = $thiscert['item'];
 			$purpose = cert_get_purpose($thiscert['crt'], true);
 			if ($purpose['server'] != "Yes") {
 				$certhelp = '<span id="certtype" class="text-danger">' . gettext("Warning: The selected server certificate was not created as an SSL/TLS Server certificate and may not work as expected") . ' </span>';
diff --git a/src/usr/local/www/wizards/openvpn_wizard.inc b/src/usr/local/www/wizards/openvpn_wizard.inc
index f0d4afb6f2..6c22156a64 100644
--- a/src/usr/local/www/wizards/openvpn_wizard.inc
+++ b/src/usr/local/www/wizards/openvpn_wizard.inc
@@ -277,6 +277,7 @@ function step9_stepbeforeformdisplay() {
 		$orgunit = $pconfig['step6']['organizationalunit'];
 	} else {
 		$ca = lookup_ca($pconfig['step6']['authcertca']);
+		$ca = $ca['item'];
 		$cavl = cert_get_subject_hash($ca['crt']);
 		$country = $cavl['C'];
 		$state = $cavl['ST'];
@@ -554,18 +555,19 @@ function step12_submitphpaction() {
 		}
 
 		ca_create($ca, $pconfig['step6']['keylength'], $pconfig['step6']['lifetime'], $dn, "sha256");
-		if (!is_array($config['ca']))
-			$config['ca'] = array();
-
-		$config['ca'][] = $ca;
+		config_set_path('ca/', $ca);
 	} else if (!isset($pconfig['step6']['uselist']) && empty($pconfig['step6']['authcertca'])) {
 		$message = "Please choose a Certificate Authority.";
 		header("Location:wizard.php?xml=openvpn_wizard.xml&stepid=5&message={$message}");
 		exit;
-	} else if (!($ca = lookup_ca($pconfig['step6']['authcertca']))) {
-		$message = "An invalid Certificate Authority has been specified.";
-		header("Location:wizard.php?xml=openvpn_wizard.xml&stepid=5&message={$message}");
-		exit;
+	} else {
+		$ca = lookup_ca($pconfig['step6']['authcertca']);
+		$ca = $ca['item'];
+		if (!$ca) {
+			$message = "An invalid Certificate Authority has been specified.";
+			header("Location:wizard.php?xml=openvpn_wizard.xml&stepid=5&message={$message}");
+			exit;
+		}
 	}
 
 	if (isset($pconfig['step9']['uselist'])) {
@@ -607,10 +609,14 @@ function step12_submitphpaction() {
 		$message = "Please choose a Certificate.";
 		header("Location:wizard.php?xml=openvpn_wizard.xml&stepid=7&message={$message}");
 		exit;
-	} else if (!($cert = lookup_cert($pconfig['step9']['authcertname']))) {
-		$message = "An invalid Certificate has been specified.";
-		header("Location:wizard.php?xml=openvpn_wizard.xml&stepid=7&message={$message}");
-		exit;
+	} else {
+		$cert = lookup_cert($pconfig['step9']['authcertname']);
+		$cert = $cert['item'];
+		if (!$cert) {
+			$message = "An invalid Certificate has been specified.";
+			header("Location:wizard.php?xml=openvpn_wizard.xml&stepid=7&message={$message}");
+			exit;
+		}
 	}
 	$server = array();
 	$server['vpnid'] = openvpn_vpnid_next();
