Internal CA Internal CA Admin path: Encryption > Internal CA ( view_internal_ca.cfm, inc/download_ca_file.cfm, inc/create_certificate.cfm, inc/send_smime_certificate.cfm, inc/delete_smime_certificate.cfm). This is the gateway's built-in Certificate Authority for issuing S/MIME certificates to local users and relay recipients. Each CA row here corresponds to a private CA cert + key on disk under /opt/hermes/CA//root_ca/ and a matching roots-store entry in the CipherMail ( djigzo) trust list. Per-recipient S/MIME certs minted from a CA on this page are stored in recipient_certificates and listed on Email Server > Relay Recipients (and Email Server > Mailboxes when S/MIME is enabled on a mailbox). This page is distinct from System Certificates: System Certificates Internal CA What it stores Operator-uploaded TLS leaf certs (nginx, Postfix, Dovecot) Private CAs that mint S/MIME end-user certs Trust direction Hermes presents these to clients Hermes issues certs that recipients present Backing store system_certificates table + /opt/hermes/ssl/ or /etc/letsencrypt/ ca_settings table + /opt/hermes/CA// + CipherMail cm_certificates ( roots store) + cm_ctl trust list Typical lifetime 90 d (ACME) or 1-3 yr (commercial) 5 yr root (recommended), extendable in place Lifecycle owner nginx / Postfix / Dovecot via TLS handshake CipherMail S/MIME signer / encryptor for outbound; per-recipient cert issuance for inbound encrypt The two ingest paths The page exposes two collapsing cards (Create Internal CA, Import External CA) plus a DataTable of existing CAs. Both paths land a row in ca_settings and register the cert in CipherMail's cm_certificates table as a root ( cm_store_name = 'roots') plus an entry in cm_ctl (Certificate Trust List) flagged whitelisted. 1. Create Internal CA Operator fills the DN fields, picks a key size (2048 / 4096) and a validity (1-5 years; 5 years recommended). Hermes: Validates inputs (regex-restricted character set per field, 2-char ISO country code, uniqueness against ca_settings.ca_commonname). Materializes a per-CA on-disk skeleton at /opt/hermes/CA//root_ca/ with the standard OpenSSL layout ( certs/, crl/, newcerts/, private/, requests/, PFX/, serial, index.txt, crlnumber). Materializes an openssl.cnf from /opt/hermes/templates/rootca_openssl.cnf with the directory placeholder substituted. Snapshots cm_certificates into cm_certificates_tmp, runs the OpenSSL root-CA generation script as a one-shot temp script ( /opt/hermes/scripts/_create_ca.sh), then diffs to find the new cert. Marks the new CipherMail row cm_store_name = 'roots', inserts a cm_ctl row with status whitelisted and allowExpired = false, and back-fills ca_settings.ca_djigzo_id + ca_djigzo_subject. 2. Import External CA For organizations that already have a private CA (commercial issuer, internal PKI, prior Hermes install). Operator uploads the CA cert (PEM) and the CA private key (PEM, unencrypted). Hermes: Lands the files at /opt/hermes/CA//root_ca/certs/cacert.pem and .../private/cakey.pem. Runs an OpenSSL validation script that checks: Cert parses as X.509 ( openssl x509 -modulus) Key parses as RSA ( openssl rsa -modulus) Cert and key moduli match (private key matches public key) Cert has CA:TRUE basic constraint On any check failure the upload directory is removed and the operator gets a specific error alert (m=48 / 49 / 50 / 51). Generates openssl.cnf from the template + cachain.pem = copy of the cert (needed for later PFX export of per-user certs). Pipes the cert into CipherMail via docker exec -i hermes_ciphermail /usr/bin/java -cp '/usr/share/djigzo/lib/*' mitm.application.djigzo.tools.CertStore --import-certificates and back-fills the ca_djigzo_id exactly as the Create path does. The Import path is the only way to migrate a CA that already has issued certs in the wild — re-creating a CA from scratch with the same DN does NOT reproduce the original key material, so previously issued certs would not chain to it. Default CA flag ( default2) Exactly one row in ca_settings has default2 = '1'; all others have '2'. The default CA is the one Hermes mints from when an admin clicks Create Certificate for a recipient on Email Server > Relay Recipients (or the mailbox equivalent) without explicitly choosing a CA. The page enforces single-default by: Setting all rows to '2' before flipping the new row to '1' Forcing the first-ever CA to default regardless of the checkbox Disabling the Make Default checkbox on the Create card when no default exists (forced default is implicit) The DataTable Default column renders a green YES badge for the default row and a one-click set default button for the others. CA lifecycle workflow +----------------+ +----------------+ +----------------+ | Admin creates |----->| CipherMail |----->| Recipient | | Internal CA | | trusts root | | cert minted | +----------------+ +----------------+ +----------------+ | v +----------------+ | Outbound mail | | signed by | | recipient cert | +----------------+ Stage Where the data lives Trigger CA root created ca_settings + /opt/hermes/CA// + cm_certificates ( roots) + cm_ctl ( whitelisted) Create / Import buttons on this page Per-recipient cert minted recipient_certificates (or external_recipient_certificates) + CipherMail user store Create Certificate button on a recipient page; uses default2 = '1' CA unless overridden Cert self-introduction Bundled into the first signed outbound message the recipient sends Automatic on first S/MIME-signed send Cert revocation delete_smime_certificate.cfm removes the row + CipherMail entry; CRL is maintained by CipherMail's own scheduled job Delete button on the recipient cert row CA renewal Re-sign the existing cert + key with openssl x509 -days and re-import into CipherMail; ca_settings.expires updated Renew button (sync icon) on the CA row CA deletion Refused if any recipient_certificates.ca_id row references it; otherwise removes DB row + CipherMail cm_certificates / cm_ctl + on-disk tree Delete button (only enabled when zero issued certs) CA Renewal: 5-year extension in place Clicking the Renew (sync) icon does NOT generate a new key pair — it re-signs the existing CA cert against its own key with an extended notAfter. The math: new_expires = current_expires + 5 years days_param = max(1825, days_from_now_to_new_expires) openssl x509 -in cacert.pem -days -out cacert.pem.new -signkey cakey.pem mv cacert.pem.new cacert.pem cp cacert.pem cachain.pem cat cacert.pem | docker exec -i hermes_ciphermail \ /usr/bin/java -cp '/usr/share/djigzo/lib/*' \ mitm.application.djigzo.tools.CertStore --import-certificates Because the key stays the same, every previously issued recipient cert still chains to a valid CA cert — there is no need to re-mint recipient certs after a CA renewal. This is the operator-friendly path: recipients on the outside who already trust the CA root continue to trust it transparently. The old CipherMail row is deleted and the renewed cert re-imported so the cm_certificates/ cm_ctl rows reflect the new validity window (otherwise CipherMail would keep enforcing the old expiry). Trust distribution to external recipients A Hermes-issued S/MIME cert is signed by a private CA that no operating system or mail client trusts by default. External recipients see Hermes-signed mail as "signed by an unknown CA" until they explicitly install the Internal CA root in their trust store. Two practical paths: Path Effort Reach Operator distributes the CA root out-of-band (download from this page, email or publish on a portal, recipient installs in Outlook / macOS Keychain / iOS Profile / Thunderbird) Manual per recipient Small fixed counterparty set (B2B, partner orgs) Issue recipient certs from a publicly-rooted CA (commercial S/MIME issuer signs your CA, or you buy per-user S/MIME certs from a public issuer) One-time cross-sign or per-user cost Every MUA on the planet trusts the chain For most Hermes deployments the Internal CA is the right answer (per-user public S/MIME costs $20-$80/yr/user); for high-volume B2C senders the publicly-rooted route is sometimes worth the cost. Hermes does not generate a CRL distribution URL on this page; CipherMail maintains the revocation list internally and applies it when verifying inbound S/MIME from local recipients. External recipients have no automatic way to consume the CRL — revocation is effectively local-only unless the operator publishes the CRL manually. CA file downloads (gated) Each row's action column exposes a Download Certificate and Download Private Key button. These are disabled by default — downloading a CA private key off a web console is a high-risk operation. To enable, set ALLOW_CA_DOWNLOAD=yes in /opt/hermes/config/security.conf on the host filesystem. This is the same toggle pattern used by System Certificates ( ALLOW_CERT_DOWNLOAD) — read on every page load, surfaced as a disabled-button + tooltip when off. When enabled, downloads stream via a hidden iframe (