diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php index 3acb96297..d148eaed6 100755 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php +++ b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php @@ -2,7 +2,7 @@ id; $cert_filename = "/var/etc/acme-client/certs/${cert_id}/cert.pem"; + $cert_chain_filename = "/var/etc/acme-client/certs/${cert_id}/chain.pem"; $cert_fullchain_filename = "/var/etc/acme-client/certs/${cert_id}/fullchain.pem"; $key_filename = "/var/etc/acme-client/keys/${cert_id}/private.key"; // Check if certificate files can be found clearstatcache(); // don't let the cache fool us - foreach (array($cert_filename, $key_filename, $cert_fullchain_filename) as $file) { + foreach (array($cert_filename, $key_filename, $cert_chain_filename, $cert_fullchain_filename) as $file) { if (is_file($file)) { // certificate file found } else { @@ -791,6 +792,63 @@ function import_certificate($certObj, $modelObj) } } + /* + * Step 1: import CA + */ + + // Read contents from CA file + $ca_content = @file_get_contents($cert_chain_filename); + if ($ca_content != false) { + $ca_subject = cert_get_subject($ca_content, false); + $ca_serial = cert_get_serial($ca_content, false); + $ca_cn = local_cert_get_cn($ca_content, false); + $ca_issuer = cert_get_issuer($ca_content, false); + $ca_purpose = cert_get_purpose($ca_content, false); + } else { + log_error("AcmeClient: unable to read CA certificate content from file"); + return(1); + } + + // Prepare CA for import in Cert Manager + $ca = array(); + $ca['crt'] = base64_encode($ca_content); + $ca['refid'] = uniqid(); + $ca_found = false; + + // Check if CA was previously imported + $cacnt = 0; + foreach ($config['ca'] as $cacrt) { + $cacrt_subject = cert_get_subject($cacrt['crt'], true); + $cacrt_issuer = cert_get_issuer($cacrt['crt'], true); + if (($ca_subject == $cacrt_subject) and ($ca_issuer == $cacrt_issuer)) { + // Use old refid instead of generating a new one + $ca['refid'] = (string)$cacrt['refid']; + $ca_found = true; + break; + } + $cacnt++; + } + + // Collect required CA information + $ca_cn = local_cert_get_cn($ca_content, false); + $ca['descr'] = (string)$ca_cn . ' (Let\'s Encrypt)'; + + // Prepare CA for import + local_ca_import($ca, $ca_content); + + // Update existing CA? + if ($ca_found == true) { + $config['ca'][$cacnt] = $ca; + } else { + // Create new CA item + $config['ca'][] = $ca; + log_error("AcmeClient: importing Let's Encrypt CA: ${ca_cn}"); + } + + /* + * Step 2: import certificate + */ + // Read contents from certificate file $cert_content = @file_get_contents($cert_filename); if ($cert_content != false) { @@ -809,6 +867,7 @@ function import_certificate($certObj, $modelObj) $cert = array(); $cert_refid = uniqid(); $cert['refid'] = $cert_refid; + $cert['caref'] = (string)$ca['refid']; $import_log_message = 'Imported'; $cert_found = false; @@ -842,20 +901,13 @@ function import_certificate($certObj, $modelObj) return(1); } - // Read cert fullchain - $cert_fullchain_content = @file_get_contents($cert_fullchain_filename); - if ($cert_fullchain_content == false) { - log_error("AcmeClient: unable to read full certificate chain from file: ${cert_fullchain_filename}"); - return(1); - } - // Collect required cert information $cert_cn = local_cert_get_cn($cert_content, false); $cert['descr'] = (string)$cert_cn . ' (Let\'s Encrypt)'; $cert['refid'] = $cert_refid; // Prepare certificate for import - cert_import($cert, $cert_fullchain_content, $key_content); + cert_import($cert, $cert_content, $key_content); // Update existing certificate? if ($cert_found == true) { @@ -874,6 +926,10 @@ function import_certificate($certObj, $modelObj) $config['cert'][] = $cert; } + /* + * Step 3: update configuration + */ + // Write changes to config // TODO: Legacy code, should be replaced with code from OPNsense framework write_config("${import_log_message} Let's Encrypt SSL certificate: ${cert_cn}"); @@ -1101,6 +1157,48 @@ function local_cert_get_cn($crt, $decode = true) return ""; } +// taken from system_camanager.php +function local_ca_import(& $ca, $str, $key="", $serial=0) { + global $config; + + $ca['crt'] = base64_encode($str); + if (!empty($key)) { + $ca['prv'] = base64_encode($key); + } + if (!empty($serial)) { + $ca['serial'] = $serial; + } + $subject = cert_get_subject($str, false); + $issuer = cert_get_issuer($str, false); + + // Find my issuer unless self-signed + if($issuer <> $subject) { + $issuer_crt =& lookup_ca_by_subject($issuer); + 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) { + $issuer = cert_get_issuer($oca['crt']); + if($ca['refid']<>$oca['refid'] && $issuer==$subject) { + $oca['caref'] = $ca['refid']; + } + } + } + if (is_array($config['cert'])) { + foreach ($config['cert'] as & $cert) { + $issuer = cert_get_issuer($cert['crt']); + if($issuer==$subject) { + $cert['caref'] = $ca['refid']; + } + } + } + return true; +} + function base64url_encode($str) { return rtrim(strtr(base64_encode($str), '+/', '-_'), '=');