From 63af2fb242ec06b71081359896482141b4f68102 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 30 Jun 2026 16:31:19 +0530 Subject: [PATCH] fix(ssl): validate custom certificate and key before install --- src/helper/class-ee-site.php | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/helper/class-ee-site.php b/src/helper/class-ee-site.php index 08ad268e..4235e5f5 100644 --- a/src/helper/class-ee-site.php +++ b/src/helper/class-ee-site.php @@ -2250,6 +2250,9 @@ protected function validate_site_custom_ssl( $ssl_key, $ssl_crt ) { } if ( $this->fs->exists( $ssl_key ) && $this->fs->exists( $ssl_crt ) ) { + // Validate cert contents before storing paths, else a malformed/mismatched pair silently breaks nginx-proxy on reload. + $this->assert_valid_cert_key_pair( file_get_contents( $ssl_crt ), file_get_contents( $ssl_key ) ); + $this->site_data['ssl_key'] = realpath( $ssl_key ); $this->site_data['ssl_crt'] = realpath( $ssl_crt ); } else { @@ -2257,6 +2260,40 @@ protected function validate_site_custom_ssl( $ssl_key, $ssl_crt ) { } } + /** + * Assert that a PEM certificate and private key are valid, matching and not expired. + * + * @param string $crt_contents Certificate file contents (PEM). + * @param string $key_contents Private key file contents (PEM). + */ + protected function assert_valid_cert_key_pair( $crt_contents, $key_contents ) { + + $cert_info = openssl_x509_parse( $crt_contents ); + if ( false === $cert_info ) { + EE::error( 'The supplied --ssl-crt is not a valid/parseable certificate.' ); + } + + if ( false === openssl_pkey_get_private( $key_contents ) ) { + EE::error( 'The supplied --ssl-key is not a valid private key.' ); + } + + if ( ! openssl_x509_check_private_key( $crt_contents, $key_contents ) ) { + EE::error( 'The supplied certificate and private key do not match.' ); + } + + // Warn (but allow) on an expired or soon-to-expire cert: clone/restore may legitimately re-supply an existing expired cert, so don't block. + if ( isset( $cert_info['validTo_time_t'] ) ) { + $now = time(); + $expiry_threshold = 30 * 24 * 60 * 60; // 30 days in seconds. + + if ( $cert_info['validTo_time_t'] < $now ) { + EE::warning( sprintf( 'The supplied certificate expired on %s.', date( 'Y-m-d', $cert_info['validTo_time_t'] ) ) ); + } elseif ( $cert_info['validTo_time_t'] - $now < $expiry_threshold ) { + EE::warning( sprintf( 'The supplied certificate expires on %s (within 30 days).', date( 'Y-m-d', $cert_info['validTo_time_t'] ) ) ); + } + } + } + /** * Allow custom SSL for site. */