Skip to content

fix(ssl): validate custom certificate and key before install - #492

Open
mrrobot47 wants to merge 3 commits into
EasyEngine:developfrom
mrrobot47:fix/validate-custom-cert
Open

mrrobot47 wants to merge 3 commits into
EasyEngine:developfrom
mrrobot47:fix/validate-custom-cert

Conversation

@mrrobot47

@mrrobot47 mrrobot47 commented Jun 30, 2026 •

Copy link
Copy Markdown
Member

Problem

validate_site_custom_ssl() only checked that the --ssl-key/--ssl-crt files exist; custom_site_ssl() then copied them into services/nginx-proxy/certs/ with no validation. A malformed PEM, or a certificate and key that don't match, silently breaks nginx-proxy on the next reload.

Fix

Add assert_valid_cert_key_pair() (called from validate_site_custom_ssl() before the paths are stored): parse the certificate (openssl_x509_parse), parse the key (openssl_pkey_get_private), and verify they match (openssl_x509_check_private_key). An unparseable certificate, an invalid key, or a key/cert mismatch are hard errors. An expired or near-expiry (< 30 days) certificate is a loud warning (not a block), so legitimate clone/restore flows that re-supply an existing certificate still proceed.

Every certificate in the file is checked, not just the first: a fullchain with a truncated or corrupt intermediate (which nginx rejects) is a hard error too.

Testing

Manual: mismatched key/crt → error; malformed PEM (e.g. DER, or a key passed as the cert) → error; truncated or corrupt chain certificate → error; expired cert → warning (proceeds); valid matching pair or fullchain → installs. The validation helper is pure and unit-testable.

Tested on Ubuntu 26.04 with EasyEngine 4.12.0 with ee site create --ssl=custom on HTML and WordPress sites: every rejected input leaves no site, certs or site dir behind and nginx -t still passes. The accept/reject results match nginx -t in the nginx-proxy image for RSA, EC and Ed25519 keys, fullchains and malformed inputs, on PHP 7.4 and 8.5.

Merge note

#489 also adds an openssl_x509_check_private_key() check to validate_site_custom_ssl(). Once both are merged, this PR's assert_valid_cert_key_pair() makes it redundant; whichever merges second should drop the duplicate.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

openssl_x509_parse() only reads the first certificate, but nginx loads every certificate in the file, so a fullchain with a truncated or corrupt intermediate passed validation and still failed nginx's config test. Check every certificate block in the file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants