PluginProbe ʕ •ᴥ•ʔ
Really Simple Security – Simple and Performant Security (formerly Really Simple SSL) / 9.5.10
Really Simple Security – Simple and Performant Security (formerly Really Simple SSL) v9.5.10
9.5.11 9.5.10.1 9.5.10 trunk 9.4.0 9.4.1 9.4.2 9.4.3 9.5.0 9.5.0.1 9.5.0.2 9.5.1 9.5.2 9.5.2.2 9.5.2.3 9.5.3 9.5.3.1 9.5.3.2 9.5.4 9.5.5 9.5.6 9.5.7 9.5.8 9.5.9
really-simple-ssl / class-certificate.php
really-simple-ssl Last commit date
assets 1 month ago core 1 month ago languages 1 month ago lets-encrypt 1 month ago lib 1 month ago mailer 1 month ago modal 1 month ago placeholders 1 month ago progress 1 month ago security 1 month ago settings 1 month ago testssl 1 month ago upgrade 1 month ago .wp-env.json 1 month ago SECURITY.md 1 month ago class-admin.php 1 month ago class-cache.php 1 month ago class-certificate.php 1 month ago class-front-end.php 1 month ago class-installer.php 1 month ago class-mixed-content-fixer.php 1 month ago class-multisite.php 1 month ago class-server.php 1 month ago class-site-health.php 1 month ago class-wp-cli.php 1 month ago compatibility.php 1 month ago force-deactivate.txt 1 month ago functions.php 1 month ago index.php 1 month ago readme.txt 1 month ago rector.php 1 month ago rlrsssl-really-simple-ssl.php 1 month ago rsssl-auto-loader.php 1 month ago sbom.json.gz 1 month ago ssl-test-page.php 1 month ago system-status.php 1 month ago uninstall.php 1 month ago upgrade.php 1 month ago
class-certificate.php
279 lines
1 <?php defined( 'ABSPATH' ) or die();
2
3 if ( ! class_exists( 'rsssl_certificate' ) ) {
4 class rsssl_certificate {
5
6 private static $_this;
7 public function __construct() {
8 if ( isset( self::$_this ) ) {
9 wp_die( 'you cannot create a second instance.' );
10 }
11 self::$_this = $this;
12 }
13
14 public static function this() {
15 return self::$_this;
16 }
17
18 /**
19 *
20 * @since 3.0
21 *
22 * Check if the certificate is valid
23 *
24 * @return bool
25 *
26 */
27
28 public function is_valid(): bool {
29 $domain = $this->get_domain();
30 if ( ! $domain || ! function_exists( 'stream_context_get_params' ) ) {
31 set_transient( 'rsssl_certinfo', 'no-response', DAY_IN_SECONDS );
32 } else {
33 $certinfo = $this->get_certinfo( $domain );
34 if ( ! $certinfo ) {
35 return false;
36 }
37
38 $domain_valid = $this->is_domain_valid( $certinfo, $domain );
39 $date_valid = $this->is_date_valid( $certinfo );
40 if ( $domain_valid && $date_valid ) {
41 return true;
42 }
43 }
44 return false;
45 }
46
47 /**
48 * get domain
49 * @return string
50 */
51 public function get_domain() {
52 $domain = site_url();
53 //Parse to strip off any /subfolder/
54 $parse = parse_url( $domain );
55 return isset( $parse['host'] ) ? $parse['host'] : false;
56 }
57
58 /**
59 *
60 * Check common name(s) and alternative name(s) on certificate and match them to the site_url ($domain)
61 *
62 * @since 3.0
63 *
64 * @access public
65 * @param $certinfo
66 * @param $domain
67 * @return bool
68 *
69 */
70
71 public function is_domain_valid( $certinfo, $domain ): bool {
72 //first check standard situation
73 //Get both the common name(s) and the alternative names from the certificate
74 $certificate_common_names = isset( $certinfo['subject']['CN'] ) ? $certinfo['subject']['CN'] : '';
75 $certificate_alternative_names = isset( $certinfo['extensions']['subjectAltName'] ) ? $certinfo['extensions']['subjectAltName'] : '';
76 //Check if the domain is found in either the certificate common name(s) (CN) or alternative name(s) (AN)
77 $pos_cn = strpos( $certificate_common_names, $domain );
78 $pos_an = strpos( $certificate_alternative_names, $domain );
79
80 //If the domain is found, return true
81 if ( false !== $pos_cn || false !== $pos_an ) {
82 return true;
83 }
84
85 //if nothing found, we check for wildcard
86 //strip of asterisk, and check if the wildcard domain is part of current domain
87 $cert_domains = array();
88 if ( $this->is_wildcard() ) {
89 $certificate_alternative_names = explode( ', ', $certificate_alternative_names );
90 $cert_domains[] = trim( str_replace( '*', '', $certificate_common_names ) );
91 foreach ( $certificate_alternative_names as $subject_alt_name ) {
92 $cert_domains[] = trim( str_replace( '*', '', $subject_alt_name ) );
93 }
94
95 foreach ( $cert_domains as $cert_domain ) {
96 //If the wildcard domain is found, return true
97 if ( ( strpos( $domain, $cert_domain ) !== false ) ) {
98 return true;
99 }
100 }
101 }
102
103 return false;
104 }
105
106 /**
107 * Check if detection failed
108 * @return bool
109 */
110 public function detection_failed() {
111 $certinfo = get_transient( 'rsssl_certinfo' );
112 if ( $certinfo && 'no-response' === $certinfo ) {
113 return true;
114 }
115
116 return false;
117 }
118
119 /**
120 *
121 * Check if the date is valid by looking at the validFrom and validTo times
122 *
123 * @since 3.0
124 *
125 * @access public
126 *
127 * @return bool
128 *
129 */
130
131 public function is_date_valid( $certinfo ) {
132
133 //Get the start date and end date from the certificate
134 $start_date = isset( $certinfo['validFrom_time_t'] ) ? $certinfo['validFrom_time_t'] : false;
135 $end_date = isset( $certinfo['validTo_time_t'] ) ? $certinfo['validTo_time_t'] : false;
136 $current_date = time();
137
138 //Check if the current date is between the start date and end date. If so, return true
139 if ( $current_date > $start_date && ( $current_date < $end_date ) ) {
140 return true;
141 }
142
143 return false;
144 }
145
146 /**
147 * Check if the certificate is valid, but about to expire.
148 * @return bool
149 */
150 public function about_to_expire() {
151 //if not valid, it's already expired
152 if ( ! $this->is_valid() ) {
153 return true;
154 }
155
156 //we have now renewed the cert info transient
157 $certinfo = get_transient( 'rsssl_certinfo' );
158 $end_date = isset( $certinfo['validTo_time_t'] ) ? $certinfo['validTo_time_t'] : false;
159 $expiry_days_time = strtotime( '+' . rsssl_le_manual_generation_renewal_check . ' days' );
160 if ( $expiry_days_time < $end_date ) {
161 return false;
162 } else {
163 return true;
164 }
165 }
166
167 /**
168 *
169 * Check if the certificate is a wildcard certificate
170 * Function is used in class-multisite.php to determine whether to show a notice for multisite subfolder installations without a wildcard certificate
171 *
172 * @since 3.0
173 *
174 * @access public
175 *
176 * @return bool
177 *
178 */
179
180 public function is_wildcard() {
181 $domain = network_site_url();
182 $certinfo = $this->get_certinfo( $domain );
183 //Get the certificate common name
184 $certificate_common_name = isset( $certinfo['subject']['CN'] ) ? $certinfo['subject']['CN'] : false;
185 $subject_alt_names = isset( $certinfo['extensions']['subjectAltName'] ) ? explode( ', ', $certinfo['extensions']['subjectAltName'] ) : false;
186
187 //Check if the common name(s) contain an *
188 if ( strpos( $certificate_common_name, '*' ) ) {
189 return true;
190 }
191
192 if ( is_array( $subject_alt_names ) ) {
193 foreach ( $subject_alt_names as $subject_alt_name ) {
194 if ( strpos( $subject_alt_name, '*' ) !== false ) {
195 return true;
196 }
197 }
198 }
199 return false;
200 }
201
202 /**
203 *
204 * Get the certificate info
205 *
206 * @since 3.0
207 * @param string $url
208 * @return string|bool
209 * @access public
210 *
211 */
212
213 public function get_certinfo( $url ) {
214 $certinfo = get_transient( 'rsssl_certinfo' );
215 //if the last check resulted in a "no response", we skip this check for a day.
216 if ( 'no-response' === $certinfo ) {
217 return false;
218 }
219
220 if ( ! $certinfo || RSSSL()->admin->is_settings_page() ) {
221 $url = 'https://' . str_replace( array( 'https://', 'http://' ), '', $url );
222 $original_parse = parse_url( $url, PHP_URL_HOST );
223 if ( $original_parse ) {
224 $get = stream_context_create( array( 'ssl' => array( 'capture_peer_cert' => true ) ) );
225 if ( $get ) {
226 set_error_handler( array( $this, 'custom_error_handling' ) );
227 $read = stream_socket_client( 'ssl://' . $original_parse . ':443', $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $get );
228 restore_error_handler();
229
230 if ( ! $read ) {
231 $certinfo = 'no-response';
232 }
233
234 if ( 0 === $errno && $read ) {
235 $cert = stream_context_get_params( $read );
236 if ( isset( $cert['options']['ssl']['peer_certificate'] ) ) {
237 $certinfo = openssl_x509_parse( $cert['options']['ssl']['peer_certificate'] );
238 } else {
239 $certinfo = 'no-response';
240 }
241 }
242 }
243 }
244 set_transient( 'rsssl_certinfo', $certinfo, DAY_IN_SECONDS );
245 }
246 if ( 'not-valid' === $certinfo ) {
247 return false;
248 }
249 if ( ! empty( $certinfo ) ) {
250 return $certinfo;
251 }
252
253 return false;
254 }
255
256 /**
257 * Catch errors
258 *
259 * @since 3.0
260 *
261 * @access public
262 * @param $errno
263 * @param $errstr
264 * @param $errfile
265 * @param $errline
266 * @param array $errcontext
267 *
268 * @return bool
269 */
270
271 public function custom_error_handling( $errno, $errstr, $errfile, $errline, $errcontext = array() ) {
272 return true;
273 }
274
275
276 //class closure
277 }
278 }
279