home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / Requests / SSL.php < prev    next >
Encoding:
PHP Script  |  2016-06-09  |  3.9 KB  |  152 lines

  1. <?php
  2. /**
  3.  * SSL utilities for Requests
  4.  *
  5.  * @package Requests
  6.  * @subpackage Utilities
  7.  */
  8.  
  9. /**
  10.  * SSL utilities for Requests
  11.  *
  12.  * Collection of utilities for working with and verifying SSL certificates.
  13.  *
  14.  * @package Requests
  15.  * @subpackage Utilities
  16.  */
  17. class Requests_SSL {
  18.     /**
  19.      * Verify the certificate against common name and subject alternative names
  20.      *
  21.      * Unfortunately, PHP doesn't check the certificate against the alternative
  22.      * names, leading things like 'https://www.github.com/' to be invalid.
  23.      * Instead
  24.      *
  25.      * @see https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
  26.      *
  27.      * @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`)
  28.      * @param string $host Host name to verify against
  29.      * @param array $cert Certificate data from openssl_x509_parse()
  30.      * @return bool
  31.      */
  32.     public static function verify_certificate($host, $cert) {
  33.         // Calculate the valid wildcard match if the host is not an IP address
  34.         $parts = explode('.', $host);
  35.         if (ip2long($host) === false) {
  36.             $parts[0] = '*';
  37.         }
  38.         $wildcard = implode('.', $parts);
  39.  
  40.         $has_dns_alt = false;
  41.  
  42.         // Check the subjectAltName
  43.         if (!empty($cert['extensions']) && !empty($cert['extensions']['subjectAltName'])) {
  44.             $altnames = explode(',', $cert['extensions']['subjectAltName']);
  45.             foreach ($altnames as $altname) {
  46.                 $altname = trim($altname);
  47.                 if (strpos($altname, 'DNS:') !== 0) {
  48.                     continue;
  49.                 }
  50.  
  51.                 $has_dns_alt = true;
  52.  
  53.                 // Strip the 'DNS:' prefix and trim whitespace
  54.                 $altname = trim(substr($altname, 4));
  55.  
  56.                 // Check for a match
  57.                 if (self::match_domain($host, $altname) === true) {
  58.                     return true;
  59.                 }
  60.             }
  61.         }
  62.  
  63.         // Fall back to checking the common name if we didn't get any dNSName
  64.         // alt names, as per RFC2818
  65.         if (!$has_dns_alt && !empty($cert['subject']['CN'])) {
  66.             // Check for a match
  67.             if (self::match_domain($host, $cert['subject']['CN']) === true) {
  68.                 return true;
  69.             }
  70.         }
  71.  
  72.         return false;
  73.     }
  74.  
  75.     /**
  76.      * Verify that a reference name is valid
  77.      *
  78.      * Verifies a dNSName for HTTPS usage, (almost) as per Firefox's rules:
  79.      * - Wildcards can only occur in a name with more than 3 components
  80.      * - Wildcards can only occur as the last character in the first
  81.      *   component
  82.      * - Wildcards may be preceded by additional characters
  83.      *
  84.      * We modify these rules to be a bit stricter and only allow the wildcard
  85.      * character to be the full first component; that is, with the exclusion of
  86.      * the third rule.
  87.      *
  88.      * @param string $reference Reference dNSName
  89.      * @return boolean Is the name valid?
  90.      */
  91.     public static function verify_reference_name($reference) {
  92.         $parts = explode('.', $reference);
  93.  
  94.         // Check the first part of the name
  95.         $first = array_shift($parts);
  96.  
  97.         if (strpos($first, '*') !== false) {
  98.             // Check that the wildcard is the full part
  99.             if ($first !== '*') {
  100.                 return false;
  101.             }
  102.  
  103.             // Check that we have at least 3 components (including first)
  104.             if (count($parts) < 2) {
  105.                 return false;
  106.             }
  107.         }
  108.  
  109.         // Check the remaining parts
  110.         foreach ($parts as $part) {
  111.             if (strpos($part, '*') !== false) {
  112.                 return false;
  113.             }
  114.         }
  115.  
  116.         // Nothing found, verified!
  117.         return true;
  118.     }
  119.  
  120.     /**
  121.      * Match a hostname against a dNSName reference
  122.      *
  123.      * @param string $host Requested host
  124.      * @param string $reference dNSName to match against
  125.      * @return boolean Does the domain match?
  126.      */
  127.     public static function match_domain($host, $reference) {
  128.         // Check if the reference is blacklisted first
  129.         if (self::verify_reference_name($reference) !== true) {
  130.             return false;
  131.         }
  132.  
  133.         // Check for a direct match
  134.         if ($host === $reference) {
  135.             return true;
  136.         }
  137.  
  138.         // Calculate the valid wildcard match if the host is not an IP address
  139.         // Also validates that the host has 3 parts or more, as per Firefox's
  140.         // ruleset.
  141.         if (ip2long($host) === false) {
  142.             $parts = explode('.', $host);
  143.             $parts[0] = '*';
  144.             $wildcard = implode('.', $parts);
  145.             if ($wildcard === $reference) {
  146.                 return true;
  147.             }
  148.         }
  149.  
  150.         return false;
  151.     }
  152. }