WP_Http_Streams::verify_ssl_certificate( resource $stream, string $host ): bool

Verifies the received SSL certificate against its Common Names and subjectAltName fields.

Description

PHP’s SSL verifications only verify that it’s a valid Certificate, it doesn’t verify if the certificate is valid for the hostname which was requested.
This function verifies the requested hostname against certificate’s subjectAltName field, if that is empty, or contains no DNS entries, a fallback to the Common Name field is used.

IP Address support is included if the request is being made to an IP address.

Parameters

$streamresourcerequired
The PHP Stream which the SSL request is being made over
$hoststringrequired
The hostname being requested

Return

bool If the certificate presented in $stream is valid for $host

Source

public static function verify_ssl_certificate( $stream, $host ) {
	$context_options = stream_context_get_options( $stream );

	if ( empty( $context_options['ssl']['peer_certificate'] ) ) {
		return false;
	}

	$cert = openssl_x509_parse( $context_options['ssl']['peer_certificate'] );
	if ( ! $cert ) {
		return false;
	}

	/*
	 * If the request is being made to an IP address, we'll validate against IP fields
	 * in the cert (if they exist)
	 */
	$host_type = ( WP_Http::is_ip_address( $host ) ? 'ip' : 'dns' );

	$certificate_hostnames = array();
	if ( ! empty( $cert['extensions']['subjectAltName'] ) ) {
		$match_against = preg_split( '/,\s*/', $cert['extensions']['subjectAltName'] );
		foreach ( $match_against as $match ) {
			list( $match_type, $match_host ) = explode( ':', $match );
			if ( strtolower( trim( $match_type ) ) === $host_type ) { // IP: or DNS:
				$certificate_hostnames[] = strtolower( trim( $match_host ) );
			}
		}
	} elseif ( ! empty( $cert['subject']['CN'] ) ) {
		// Only use the CN when the certificate includes no subjectAltName extension.
		$certificate_hostnames[] = strtolower( $cert['subject']['CN'] );
	}

	// Exact hostname/IP matches.
	if ( in_array( strtolower( $host ), $certificate_hostnames, true ) ) {
		return true;
	}

	// IP's can't be wildcards, Stop processing.
	if ( 'ip' === $host_type ) {
		return false;
	}

	// Test to see if the domain is at least 2 deep for wildcard support.
	if ( substr_count( $host, '.' ) < 2 ) {
		return false;
	}

	// Wildcard subdomains certs (*.example.com) are valid for a.example.com but not a.b.example.com.
	$wildcard_host = preg_replace( '/^[^.]+\./', '*.', $host );

	return in_array( strtolower( $wildcard_host ), $certificate_hostnames, true );
}

Changelog

VersionDescription
3.7.0Introduced.

User Contributed Notes

You must log in before being able to contribute a note or feedback.