/
home
/
sjslayjy
/
public_html
/
theweavenest
/
vendor
/
rmccue
/
requests
/
tests
/
Upload File
HOME
<?php namespace WpOrg\Requests\Tests; use stdClass; use WpOrg\Requests\Exception\InvalidArgument; use WpOrg\Requests\Ssl; use WpOrg\Requests\Tests\Fixtures\StringableObject; use WpOrg\Requests\Tests\TestCase; /** * @coversDefaultClass \WpOrg\Requests\Ssl */ final class SslTest extends TestCase { /** * Test handling of matching host and DNS names. * * @dataProvider dataMatch * * @covers ::match_domain * * @param string $host Host name to verify. * @param string $reference DNS name to match against. * * @return void */ public function testMatch($host, $reference) { $this->assertTrue(Ssl::match_domain($host, $reference)); } /** * Test handling of matching host and DNS names based on certificate. * * @dataProvider dataMatch * @dataProvider dataMatchViaCertificate * * @covers ::verify_certificate * * @param string $host Host name to verify. * @param string $reference DNS name to match against. * @param bool|string $with_san Optional. How to generate the fake certificate. * - false: plain, CN only; * - true: CN + subjectAltName, alt set to same as CN; * - string: CN + subjectAltName, alt set to string value. * * @return void */ public function testMatchViaCertificate($host, $reference, $with_san = true) { $certificate = $this->fakeCertificate($reference, $with_san); $this->assertTrue(Ssl::verify_certificate($host, $certificate)); } /** * Data provider. * * @return array */ public function dataMatch() { return [ 'top-level domain (stringable object)' => [ 'host' => new StringableObject('example.com'), 'reference' => new StringableObject('example.com'), ], 'subdomain' => [ 'host' => 'test.example.com', 'reference' => 'test.example.com', ], 'subdomain with wildcard reference' => [ 'host' => 'test.example.com', 'reference' => '*.example.com', ], ]; } /** * Data provider for additional test cases specific to the Ssl::verify_certificate() method. * * @return array */ public function dataMatchViaCertificate() { return [ 'top-level domain; missing SAN, fallback to CN' => [ 'host' => 'example.com', 'reference' => 'example.com', 'with_san' => false, ], 'SAN available, multiple alternatives provided; matching is second' => [ 'host' => 'example.net', 'reference' => 'example.net', 'with_san' => 'DNS: example.com, DNS: example.net, DNS: example.info', ], 'SAN available, multiple alternatives provided; matching is last' => [ 'host' => 'example.net', 'reference' => 'example.net', 'with_san' => 'DNS: example.com, DNS: example.org, DNS: example.net', ], 'SAN available, DNS prefix missing in first, not (matching) second' => [ 'host' => 'example.net', 'reference' => 'example.com', 'with_san' => 'example.com, DNS: example.net', ], 'SAN available, DNS prefix missing in all, fallback to CN' => [ 'host' => 'example.net', 'reference' => 'example.net', 'with_san' => 'example.com, example.net', ], ]; } /** * Test handling of non-matching host and DNS names. * * @dataProvider dataNoMatch * * @covers ::match_domain * * @param string $host Host name to verify. * @param string $reference DNS name to match against. * * @return void */ public function testNoMatch($host, $reference) { $this->assertFalse(Ssl::match_domain($host, $reference)); } /** * Test handling of non-matching host and DNS names based on certificate. * * @dataProvider dataNoMatch * @dataProvider dataNoMatchViaCertificate * * @covers ::verify_certificate * * @param string $host Host name to verify. * @param string $reference DNS name to match against. * @param bool|string $with_san Optional. How to generate the fake certificate. * - false: plain, CN only; * - true: CN + subjectAltName, alt set to same as CN; * - string: CN + subjectAltName, alt set to string value. * * @return void */ public function testNoMatchViaCertificate($host, $reference, $with_san = true) { $certificate = $this->fakeCertificate($reference, $with_san); $this->assertFalse(Ssl::verify_certificate($host, $certificate)); } /** * Data provider. * * @return array */ public function dataNoMatch() { return [ // Check that we need at least 3 components 'not a domain; wildcard reference' => [ 'host' => 'com', 'reference' => '*', ], 'domain name; wildcard on TLD as reference' => [ 'host' => 'example.com', 'reference' => '*.com', ], // Check that double wildcards don't work 'domain name; double wildcard in reference' => [ 'host' => 'abc.def.example.com', 'reference' => '*.*.example.com', ], // Check that we only match with the correct number of components 'four-level domain; three-level reference' => [ 'host' => 'abc.def.example.com', 'reference' => 'def.example.com', ], 'four-level domain; three-level wildcard reference' => [ 'host' => 'abc.def.example.com', 'reference' => '*.example.com', ], // Check that the wildcard only works as the full first component 'four-level domain; four-level reference, but wildcard not stand-alone' => [ 'host' => 'abc.def.example.com', 'reference' => 'a*.def.example.com', ], // Check that wildcards are not allowed for IPs 'IP address; wildcard in refence (start)' => [ 'host' => '192.168.0.1', 'reference' => '*.168.0.1', ], 'IP address; wildcard in refence (end)' => [ 'host' => '192.168.0.1', 'reference' => '192.168.0.*', ], // IP vs named address. 'IP address vs named address' => [ 'host' => '192.168.0.1', 'reference' => '*.example.com', ], 'Named address vs IP address' => [ 'host' => 'example.com', 'reference' => '192.168.0.1', ], ]; } /** * Data provider for additional test cases specific to the Ssl::verify_certificate() method. * * @return array */ public function dataNoMatchViaCertificate() { return [ 'top-level domain; missing SAN, fallback to invalid CN' => [ 'host' => 'example.net', 'reference' => 'example.com', 'with_san' => false, ], 'SAN empty' => [ 'host' => 'example.net', 'reference' => 'example.com', 'with_san' => '', ], 'SAN available, DNS prefix missing' => [ 'host' => 'example.net', 'reference' => 'example.com', 'with_san' => 'example.com', ], 'SAN available, multiple alternatives provided; none of the SANs match, DNS prefix missing in first, not second' => [ 'host' => 'example.net', 'reference' => 'example.com', 'with_san' => 'example.com, DNS: example.org', ], 'SAN available, multiple alternatives provided; none of the SANs match, even though CN does' => [ 'host' => 'example.net', 'reference' => 'example.net', 'with_san' => 'DNS: example.com, DNS: example.org, DNS: example.info', ], ]; } /** * Test helper to mock a certificate. * * @param string $dnsname DNS name to match against. * @param bool|string $with_san Optional. How to generate the fake certificate. * - false: plain, CN only; * - true: CN + subjectAltName, alt set to same as CN; * - string: CN + subjectAltName, alt set to string value. * * @return array */ private function fakeCertificate($dnsname, $with_san = true) { $certificate = [ 'subject' => [ 'CN' => $dnsname, ], ]; if ($with_san !== false) { // If SAN is set to true, default it to the dNSName if ($with_san === true) { $with_san = 'DNS: ' . $dnsname; } $certificate['extensions'] = [ 'subjectAltName' => $with_san, ]; } return $certificate; } /** * Test a certificate with both CN and SAN fields * * As per RFC2818, if the SAN field exists, we should parse that and ignore * the value of the CN field. * * @link https://tools.ietf.org/html/rfc2818#section-3.1 * * @covers ::verify_certificate */ public function testIgnoreCNWithSAN() { $certificate = $this->fakeCertificate('example.net', 'DNS: example.com'); $this->assertTrue(Ssl::verify_certificate('example.com', $certificate), 'Checking SAN validation'); $this->assertFalse(Ssl::verify_certificate('example.net', $certificate), 'Checking CN non-validation'); } /** * Test handling of non-compliant certificates. * * @dataProvider dataVerifyCertificateWithInvalidCertificates * * @param string $host Host name to verify. * @param array $certificate A (faked) certificate to verify against. * @param bool $expected Expected function output. * * @return void */ public function testVerifyCertificateWithInvalidCertificates($host, $certificate, $expected) { $this->assertSame($expected, Ssl::verify_certificate($host, $certificate)); } /** * Data provider. * * @return array */ public function dataVerifyCertificateWithInvalidCertificates() { return [ 'empty array' => [ 'host' => 'example.com', 'certificate' => [], 'expected' => false, ], 'subject, but missing CN entry; no SAN' => [ 'host' => 'example.com', 'certificate' => [ 'subject' => [], ], 'expected' => false, ], 'subject with empty CN entry; no SAN' => [ 'host' => 'example.com', 'certificate' => [ 'subject' => [ 'CN' => '', ], ], 'expected' => false, ], 'subject, but missing CN entry; SAN exists, missing DNS' => [ 'host' => 'example.com', 'certificate' => [ 'subject' => [], 'extensions' => [ 'subjectAltName' => 'example.net', ], ], 'expected' => false, ], 'subject with empty CN entry; SAN exists, missing DNS' => [ 'host' => 'example.com', 'certificate' => [ 'subject' => [ 'CN' => '', ], 'extensions' => [ 'subjectAltName' => 'example.net', ], ], 'expected' => false, ], 'subject, but missing CN entry; SAN exists, but non-matching' => [ 'host' => 'example.com', 'certificate' => [ 'subject' => [], 'extensions' => [ 'subjectAltName' => 'DNS: example.net', ], ], 'expected' => false, ], 'subject with empty CN entry; SAN exists, but non-matching' => [ 'host' => 'example.com', 'certificate' => [ 'subject' => [ 'CN' => '', ], 'extensions' => [ 'subjectAltName' => 'DNS: example.net', ], ], 'expected' => false, ], 'extensions, but missing SAN entry' => [ 'host' => 'example.com', 'certificate' => [ 'subject' => [ 'CN' => 'example.net', ], 'extensions' => [], ], 'expected' => false, ], 'extensions with empty SAN entry' => [ 'host' => 'example.com', 'certificate' => [ 'subject' => [ 'CN' => 'example.net', ], 'extensions' => [ 'subjectAltName' => '', ], ], 'expected' => false, ], ]; } /** * Test correctly identifying whether a reference name is valid. * * @covers ::verify_reference_name * * @dataProvider dataVerifyReferenceName * * @param string $reference Reference name to test. * @param bool $expected Expected function outcome. * * @return void */ public function testVerifyReferenceName($reference, $expected) { $this->assertSame($expected, Ssl::verify_reference_name($reference)); } /** * Data provider. * * @return array */ public function dataVerifyReferenceName() { return [ 'empty string' => [ 'reference' => '', 'expected' => false, ], 'one part, no dot' => [ 'reference' => 'example', 'expected' => true, ], 'one part, only wildcard' => [ 'reference' => '*', 'expected' => false, ], 'two parts, no wildcard' => [ 'reference' => 'example.com', 'expected' => true, ], 'two parts, wildcard in first' => [ 'reference' => '*.com', 'expected' => false, ], 'two parts, wildcard in last' => [ 'reference' => 'example.*', 'expected' => false, ], 'three parts, only dots' => [ 'reference' => '..', 'expected' => false, ], 'three parts, no wildcard' => [ 'reference' => new StringableObject('www.example.com'), 'expected' => true, ], 'three parts, no wildcard, has spaces' => [ 'reference' => 'my dog . and . my cat', 'expected' => false, ], 'three parts, wildcard in first' => [ 'reference' => '*.example.com', 'expected' => true, ], 'three parts, wildcard in second' => [ 'reference' => 'www.*.com', 'expected' => false, ], 'three parts, wildcard in third' => [ 'reference' => 'www.example.*', 'expected' => false, ], 'three parts, wildcard in first at start with other characters' => [ 'reference' => '*ww.example.com', 'expected' => false, ], 'three parts, wildcard in first at end with other characters' => [ 'reference' => 'ww*.example.com', 'expected' => false, ], 'three parts, wildcard in first and second' => [ 'reference' => '*.*.com', 'expected' => false, ], 'three parts, wildcard in second and last' => [ 'reference' => 'www.*.*', 'expected' => false, ], 'three parts, wildcard in first and last' => [ 'reference' => '*.example.*', 'expected' => false, ], ]; } /** * Tests receiving an exception when an invalid input type is passed as $host. * * @dataProvider dataInvalidInputType * * @covers ::verify_certificate * * @param mixed $input Input data. * * @return void */ public function testVerifyCertificateInvalidInputHost($input) { $this->expectException(InvalidArgument::class); $this->expectExceptionMessage('Argument #1 ($host) must be of type string|Stringable'); Ssl::verify_certificate($input, []); } /** * Tests receiving an exception when an invalid input type is passed as $cert. * * @dataProvider dataInvalidInputType * * @covers ::verify_certificate * * @param mixed $input Input data. * * @return void */ public function testVerifyCertificateInvalidInputCert($input) { $this->expectException(InvalidArgument::class); $this->expectExceptionMessage('Argument #2 ($cert) must be of type array|ArrayAccess'); Ssl::verify_certificate('host', $input); } /** * Tests receiving an exception when an invalid input type is passed. * * @dataProvider dataInvalidInputType * * @covers ::verify_reference_name * * @param mixed $input Input data. * * @return void */ public function testVerifyReferenceNameInvalidInputType($input) { $this->expectException(InvalidArgument::class); $this->expectExceptionMessage('Argument #1 ($reference) must be of type string|Stringable'); Ssl::verify_reference_name($input); } /** * Tests receiving an exception when an invalid input type is passed. * * @dataProvider dataInvalidInputType * * @covers ::match_domain * * @param mixed $input Input data. * * @return void */ public function testInvalidInputType($input) { $this->expectException(InvalidArgument::class); $this->expectExceptionMessage('Argument #1 ($host) must be of type string|Stringable'); Ssl::match_domain($input, 'reference'); } /** * Data Provider. * * @return array */ public function dataInvalidInputType() { return [ 'null' => [null], 'plain object' => [new stdClass()], ]; } }