2016-05-13 06:42:28 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* SSL utilities for Requests
|
|
|
|
*
|
|
|
|
* @package Requests
|
|
|
|
* @subpackage Utilities
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SSL utilities for Requests
|
|
|
|
*
|
|
|
|
* Collection of utilities for working with and verifying SSL certificates.
|
|
|
|
*
|
|
|
|
* @package Requests
|
|
|
|
* @subpackage Utilities
|
|
|
|
*/
|
|
|
|
class Requests_SSL {
|
|
|
|
/**
|
|
|
|
* Verify the certificate against common name and subject alternative names
|
|
|
|
*
|
|
|
|
* Unfortunately, PHP doesn't check the certificate against the alternative
|
|
|
|
* names, leading things like 'https://www.github.com/' to be invalid.
|
|
|
|
* Instead
|
|
|
|
*
|
2016-06-10 06:50:33 +02:00
|
|
|
* @see https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
|
2016-05-13 06:42:28 +02:00
|
|
|
*
|
|
|
|
* @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`)
|
|
|
|
* @param string $host Host name to verify against
|
|
|
|
* @param array $cert Certificate data from openssl_x509_parse()
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public static function verify_certificate($host, $cert) {
|
|
|
|
// Calculate the valid wildcard match if the host is not an IP address
|
|
|
|
$parts = explode('.', $host);
|
|
|
|
if (ip2long($host) === false) {
|
|
|
|
$parts[0] = '*';
|
|
|
|
}
|
|
|
|
$wildcard = implode('.', $parts);
|
|
|
|
|
|
|
|
$has_dns_alt = false;
|
|
|
|
|
|
|
|
// Check the subjectAltName
|
|
|
|
if (!empty($cert['extensions']) && !empty($cert['extensions']['subjectAltName'])) {
|
|
|
|
$altnames = explode(',', $cert['extensions']['subjectAltName']);
|
|
|
|
foreach ($altnames as $altname) {
|
|
|
|
$altname = trim($altname);
|
|
|
|
if (strpos($altname, 'DNS:') !== 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$has_dns_alt = true;
|
|
|
|
|
|
|
|
// Strip the 'DNS:' prefix and trim whitespace
|
|
|
|
$altname = trim(substr($altname, 4));
|
|
|
|
|
|
|
|
// Check for a match
|
|
|
|
if (self::match_domain($host, $altname) === true) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fall back to checking the common name if we didn't get any dNSName
|
|
|
|
// alt names, as per RFC2818
|
|
|
|
if (!$has_dns_alt && !empty($cert['subject']['CN'])) {
|
|
|
|
// Check for a match
|
|
|
|
if (self::match_domain($host, $cert['subject']['CN']) === true) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Verify that a reference name is valid
|
|
|
|
*
|
|
|
|
* Verifies a dNSName for HTTPS usage, (almost) as per Firefox's rules:
|
|
|
|
* - Wildcards can only occur in a name with more than 3 components
|
|
|
|
* - Wildcards can only occur as the last character in the first
|
|
|
|
* component
|
|
|
|
* - Wildcards may be preceded by additional characters
|
|
|
|
*
|
|
|
|
* We modify these rules to be a bit stricter and only allow the wildcard
|
|
|
|
* character to be the full first component; that is, with the exclusion of
|
|
|
|
* the third rule.
|
|
|
|
*
|
|
|
|
* @param string $reference Reference dNSName
|
|
|
|
* @return boolean Is the name valid?
|
|
|
|
*/
|
|
|
|
public static function verify_reference_name($reference) {
|
|
|
|
$parts = explode('.', $reference);
|
|
|
|
|
|
|
|
// Check the first part of the name
|
|
|
|
$first = array_shift($parts);
|
|
|
|
|
|
|
|
if (strpos($first, '*') !== false) {
|
|
|
|
// Check that the wildcard is the full part
|
|
|
|
if ($first !== '*') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that we have at least 3 components (including first)
|
|
|
|
if (count($parts) < 2) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the remaining parts
|
|
|
|
foreach ($parts as $part) {
|
|
|
|
if (strpos($part, '*') !== false) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nothing found, verified!
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Match a hostname against a dNSName reference
|
|
|
|
*
|
|
|
|
* @param string $host Requested host
|
|
|
|
* @param string $reference dNSName to match against
|
|
|
|
* @return boolean Does the domain match?
|
|
|
|
*/
|
|
|
|
public static function match_domain($host, $reference) {
|
General: Remove “whitelist” and “blacklist” in favor of more clear and inclusive language.
“The WordPress open source community cares about diversity. We strive to maintain a welcoming environment where everyone can feel included.”
With this commit, all occurrences of “whitelist” and “blacklist” (with the single exception of the `$new_whitelist_options` global variable) are removed. A new ticket has been opened to explore renaming the `$new_whitelist_options` variable (#50434).
Changing to more specific names or rewording sentences containing these terms not only makes the code more inclusive, but also helps provide clarity. These terms are often ambiguous. What is being blocked or allowed is not always immediately clear. This can make it more difficult for non-native English speakers to read through the codebase.
Words matter. If one contributor feels more welcome because these terms are removed, this was worth the effort.
Props strangerstudios, jorbin, desrosj, joemcgill, timothyblynjacobs, ocean90, ayeshrajans, davidbaumwald, earnjam.
See #48900, #50434.
Fixes #50413.
Built from https://develop.svn.wordpress.org/trunk@48121
git-svn-id: http://core.svn.wordpress.org/trunk@47890 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2020-06-22 19:26:13 +02:00
|
|
|
// Check if the reference is blocklisted first
|
2016-05-13 06:42:28 +02:00
|
|
|
if (self::verify_reference_name($reference) !== true) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for a direct match
|
|
|
|
if ($host === $reference) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate the valid wildcard match if the host is not an IP address
|
|
|
|
// Also validates that the host has 3 parts or more, as per Firefox's
|
|
|
|
// ruleset.
|
|
|
|
if (ip2long($host) === false) {
|
|
|
|
$parts = explode('.', $host);
|
|
|
|
$parts[0] = '*';
|
|
|
|
$wildcard = implode('.', $parts);
|
|
|
|
if ($wildcard === $reference) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
General: Remove “whitelist” and “blacklist” in favor of more clear and inclusive language.
“The WordPress open source community cares about diversity. We strive to maintain a welcoming environment where everyone can feel included.”
With this commit, all occurrences of “whitelist” and “blacklist” (with the single exception of the `$new_whitelist_options` global variable) are removed. A new ticket has been opened to explore renaming the `$new_whitelist_options` variable (#50434).
Changing to more specific names or rewording sentences containing these terms not only makes the code more inclusive, but also helps provide clarity. These terms are often ambiguous. What is being blocked or allowed is not always immediately clear. This can make it more difficult for non-native English speakers to read through the codebase.
Words matter. If one contributor feels more welcome because these terms are removed, this was worth the effort.
Props strangerstudios, jorbin, desrosj, joemcgill, timothyblynjacobs, ocean90, ayeshrajans, davidbaumwald, earnjam.
See #48900, #50434.
Fixes #50413.
Built from https://develop.svn.wordpress.org/trunk@48121
git-svn-id: http://core.svn.wordpress.org/trunk@47890 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2020-06-22 19:26:13 +02:00
|
|
|
}
|