From f0dbc03e8e177d2ac4dd3cba29ae0b68d3ea3292 Mon Sep 17 00:00:00 2001 From: Sebastiaan Stok Date: Fri, 22 Dec 2023 13:49:50 +0100 Subject: [PATCH 1/3] Run OCSP revocation test with actual connection And include CA issuer information in the violation to make finding the missing parent CA easier And increased CA list limit to 4 --- .../translations/validators+intl-icu.en.xliff | 4 +- src/CAResolverImpl.php | 6 +- src/Violation/UnableToResolveParent.php | 12 +- src/X509DataExtractor.php | 2 +- tests/CAResolverImplTest.php | 29 +++ tests/OCSPValidatorTest.php | 207 +++++++++--------- 6 files changed, 138 insertions(+), 122 deletions(-) diff --git a/Resources/translations/validators+intl-icu.en.xliff b/Resources/translations/validators+intl-icu.en.xliff index f78467e..ef8b4d5 100644 --- a/Resources/translations/validators+intl-icu.en.xliff +++ b/Resources/translations/validators+intl-icu.en.xliff @@ -51,8 +51,8 @@ The certificate host "{provided}" contains an invalid public-suffix wildcard pattern "{suffix_pattern}". - Unable to resolve CA of certificate "{name}". - Unable to resolve CA of certificate "{name}". + Unable to resolve the CA of certificate "{name}", issued by {parent}. + Unable to resolve the CA of certificate "{name}", issued by {parent}. diff --git a/src/CAResolverImpl.php b/src/CAResolverImpl.php index e599468..4e36bae 100644 --- a/src/CAResolverImpl.php +++ b/src/CAResolverImpl.php @@ -35,7 +35,7 @@ public function resolve(string $certificate, array $caList): ?CA { // Safety check to prevent DoS attacks // Normally only two parents are used, more than three is exceptional - if (\count($caList) > 3) { + if (\count($caList) > 4) { throw new ToManyCAsProvided(); } @@ -84,7 +84,9 @@ private function resolveCA(string $certificate, array $caList): CA return new CA($contents); } - throw new UnableToResolveParent($this->extractor->extractRawData($certificate)->commonName); + $x509Info = $this->extractor->extractRawData($certificate); + + throw new UnableToResolveParent($x509Info->commonName, $x509Info->allFields['issuer']['commonName']); } private function validateCA(X509Info $data): void diff --git a/src/Violation/UnableToResolveParent.php b/src/Violation/UnableToResolveParent.php index 3296a03..78f118a 100644 --- a/src/Violation/UnableToResolveParent.php +++ b/src/Violation/UnableToResolveParent.php @@ -17,22 +17,18 @@ final class UnableToResolveParent extends Violation { - private readonly string $name; - - public function __construct(string $name, int $code = 1) + public function __construct(private readonly string $name, private readonly string $issuer, int $code = 1) { - parent::__construct(sprintf('Unable to resolve the parent CA of certificate "%s".', $name), $code); - - $this->name = $name; + parent::__construct(sprintf('Unable to resolve the parent CA of certificate "%s", issued by "%s".', $name, $issuer), $code); } public function getTranslatorMsg(): string { - return 'Unable to resolve the CA of certificate "{name}".'; + return 'Unable to resolve the CA of certificate "{name}", issued by {parent}.'; } public function getParameters(): array { - return ['name' => $this->name]; + return ['name' => $this->name, 'parent' => $this->issuer]; } } diff --git a/src/X509DataExtractor.php b/src/X509DataExtractor.php index 90a7bba..deb9f14 100644 --- a/src/X509DataExtractor.php +++ b/src/X509DataExtractor.php @@ -46,7 +46,7 @@ public function extractRawData(string $contents, string $name = '', bool $withPu } try { - $fingerprint = openssl_x509_fingerprint($x509Read, $rawData['signatureTypeSN']) ?: ''; + $fingerprint = @openssl_x509_fingerprint($x509Read, $rawData['signatureTypeSN']) ?: ''; } catch (\Throwable) { $fingerprint = ''; } diff --git a/tests/CAResolverImplTest.php b/tests/CAResolverImplTest.php index 9318995..fc126ea 100644 --- a/tests/CAResolverImplTest.php +++ b/tests/CAResolverImplTest.php @@ -240,6 +240,35 @@ public function it_fails_with_to_many_cas_provided(): void j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz -----END CERTIFICATE----- CERT, + 'ca45' => <<<'CERT' + -----BEGIN CERTIFICATE----- + MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh + MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 + d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD + QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT + MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg + U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB + ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83 + nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd + KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f + /ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX + kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0 + /RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C + AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY + aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6 + Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1 + oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD + QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v + d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh + xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB + CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl + 5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA + 8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC + 2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit + c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0 + j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz + -----END CERTIFICATE----- + CERT, ] ); } diff --git a/tests/OCSPValidatorTest.php b/tests/OCSPValidatorTest.php index d1e58a7..a5ce20d 100644 --- a/tests/OCSPValidatorTest.php +++ b/tests/OCSPValidatorTest.php @@ -14,7 +14,6 @@ namespace Rollerworks\Component\X509Validator\Tests; use Ocsp\Ocsp; -use Ocsp\Response as OcspResponse; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use Prophecy\Argument; @@ -99,140 +98,130 @@ public function validate_certificate_is_revoked(): void { $certContents = <<<'CERT' -----BEGIN CERTIFICATE----- - MIIHGTCCBgGgAwIBAgIQBh3eOmYhdHQ4TTZVG+hHijANBgkqhkiG9w0BAQsFADBN - MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E - aWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgwMjA4MDAwMDAwWhcN - MjEwMjEyMTIwMDAwWjBpMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNV - BAcTDVNhbiBGcmFuY2lzY28xITAfBgNVBAoTGFNsYWNrIFRlY2hub2xvZ2llcywg - SW5jLjESMBAGA1UEAxMJc2xhY2suY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A - MIIBCgKCAQEAqb0QCgBUkwHwC1AUT1N1W6wfbKSUZGSQ9Pf7EovdVIt1f8hrq5KZ - OvVUaU/5qsS9UMm1GGqhjVrFqRKv//rZ/VaIThNaLVGQ3yTWCmnPxTZBvEOH1oLP - i2V+XgDcX2drRUUfFELQy8EZVABwQu5Y3FluB1S7Nv1EH2tOsug5koMIdtMetUo/ - nKPzpuVC/4C/8oPN3+37cSriAImfxrifrrSCLkMscnwh6VcSuajnlCgw/iVcQzEE - 0OGht+KmFgIvjTWmKLx44MvkKqPUnvBudKk4k+9V527g9uNM0rxCVXWb1hf5w08I - VvEC5/N78HrBl/q/e2oaygp95z/CQ5aJqQIDAQABo4ID1zCCA9MwHwYDVR0jBBgw - FoAUD4BhHIIxYdUvKOeNRji0LOHG2eIwHQYDVR0OBBYEFPla7+E8XELNsM7Mg46q - uGwJyd0tMCEGA1UdEQQaMBiCCXNsYWNrLmNvbYILKi5zbGFjay5jb20wDgYDVR0P - AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8E - ZDBiMC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2 - LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1n - Ni5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0 - cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEE - cDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYB - BQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJT - ZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAfYGCisGAQQB1nkCBAIE - ggHmBIIB4gHgAHYApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFh - d2Q95wAABAMARzBFAiEA42uacv79w94og76vu/L9nzZJAsU0398rJZuBAY8EY30C - IFCuAzawnV4AOtOEEp7ybdy/0SLBgZ7bBO3gs0EhkOYCAHYAh3W/51l8+IxDmV+9 - 827/Vo1HVjb/SrVgwbTq/16ggw8AAAFhd2Q9zQAABAMARzBFAiBIhbiWxOmsFEmC - 2I6ZBg8Qb+xSIv0AgqZTnIHSzaR0BwIhALoijpGV0JB2xBgW88noxeHdCeqWXQ/a - HPDAd/Q37M+WAHYAu9nfvB+KcbWTlCOXqpJ7RzhXlQqrUugakJZkNo4e0YUAAAFh - d2Q+IAAABAMARzBFAiEA0p6Cq67EzeVhxYSpNJYU8Ys7Pj9c4EQPmPaAvnLDL0wC - IBnOHO2DWoBi+LH6Z/uicH+4nbb4S15zV96NqFn9mXH0AHYAb1N2rDHwMRnYmQCk - URX/dxUcEdkCwQApBo2yCJo32RMAAAFhd2Q/4AAABAMARzBFAiEA2C3VUu67nO5T - e2Q8okaIkPftUdE+GHyKkZbqmJMg550CIBFZW53z4BUmtP4GDBEA85D/EnDBPOx2 - OC6cgoRW7sz/MA0GCSqGSIb3DQEBCwUAA4IBAQBUh0yybzRV4ednO+RM4uifnBkf - S/9r4IHqvFyYgyofd1hygwD3i/pT10V+yF2teqL/FuwsInbjrvGpwFH/uiuhGgzc - hJ5TOA0/+A/RYNo7sN7An9NBYvedJOlV0iDUhVuQpGefEY3VHqtg0qNu9YoAAl67 - pDCmmQQoNKHDdq2IFq8taF8ros+stqC+cPBipVLxXe9wAFnTkjq0VjB1VqKzLDQ+ - VGN9QV+gw0KI7opJ4K/UKOTnG7ON0zlKIqAK2pXUVsQa9Q5kMbakOk3930bGrkXW - dqEt/Oc2qDvj/OFnFvaAiKhWUmwhu3IJT4B+W15sPYYBAC4N4FhjP+aGv6IK + MIIG4DCCBmagAwIBAgIQBZy2esMzb+7oVrJyhjxvUzAKBggqhkjOPQQDAzBUMQsw + CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xLDAqBgNVBAMTI0Rp + Z2lDZXJ0IEc1IFRMUyBFQ0MgU0hBMzg0IDIwMjEgQ0ExMB4XDTIzMDMxNjAwMDAw + MFoXDTI0MDQxNTIzNTk1OVowge8xEzARBgsrBgEEAYI3PAIBAxMCVVMxFTATBgsr + BgEEAYI3PAIBAhMEVXRhaDEdMBsGA1UEDwwUUHJpdmF0ZSBPcmdhbml6YXRpb24x + FTATBgNVBAUTDDUyOTk1MzctMDE0MjELMAkGA1UEBhMCVVMxDTALBgNVBAgTBFV0 + YWgxDTALBgNVBAcTBExlaGkxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUcwRQYD + VQQDEz5kaWdpY2VydC10bHMtZWNjLXAzODQtcm9vdC1nNS1yZXZva2VkLmNoYWlu + LWRlbW9zLmRpZ2ljZXJ0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC + ggEBAK3SEGd7aOOyi9rknL/GpNSovKvxOeJzrpO7Spq1Ag7KeAtx6kYDm7xgvOXM + EPPylKDCvtXl1ic+PYBBVpNZEhHTVefdb9CzsTEcOYLaPFIAOnmie1HHczY57H2f + JqvaYqE4VJWAHWuGMf90ZYSkqtoGJJsnLs/Ajd3lawIeUwPCDdWKQiUVG53Ruk5G + KRct/Jnxo2qX1GMPt63Q4nvjb0p+4UvWYfBSCAD6UehkdGb1RkbEgKxwBUbFzh7p + dQ1WDIVzV0C6OPdt4LUqvVYVw9DpmMSF3YUOvvDEhx1w5bR8JIzmlFYP/IMBx1Bl + a9WWbVjCbASq6Z4XrWMpgNoYBEkCAwEAAaOCA7EwggOtMB8GA1UdIwQYMBaAFJtY + 3I2mZZjnvAb+GqQVoG/L5qmQMB0GA1UdDgQWBBSsdJukmxK5PpB8IpqyeWO1KJt1 + EzBJBgNVHREEQjBAgj5kaWdpY2VydC10bHMtZWNjLXAzODQtcm9vdC1nNS1yZXZv + a2VkLmNoYWluLWRlbW9zLmRpZ2ljZXJ0LmNvbTAOBgNVHQ8BAf8EBAMCBaAwHQYD + VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGTBgNVHR8EgYswgYgwQqBAoD6G + PGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEc1VExTRUNDU0hBMzg0 + MjAyMUNBMS0xLmNybDBCoECgPoY8aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0Rp + Z2lDZXJ0RzVUTFNFQ0NTSEEzODQyMDIxQ0ExLTEuY3JsMEoGA1UdIARDMEEwCwYJ + YIZIAYb9bAIBMDIGBWeBDAEBMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGln + aWNlcnQuY29tL0NQUzCBgQYIKwYBBQUHAQEEdTBzMCQGCCsGAQUFBzABhhhodHRw + Oi8vb2NzcC5kaWdpY2VydC5jb20wSwYIKwYBBQUHMAKGP2h0dHA6Ly9jYWNlcnRz + LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEc1VExTRUNDU0hBMzg0MjAyMUNBMS0xLmNy + dDAJBgNVHRMEAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdgDuzdBk1dsa + zsVct520zROiModGfLzs3sNRSFlGcR+1mwAAAYbrrv/aAAAEAwBHMEUCIBj/mZ6B + QbGrMpNBZoWihQ7+ckmYk1ZbEi/sxPFluT++AiEAzdLuAClGxj5Qw/9yv9XcuVgo + LJxuiPNFmI3cifmpY/UAdwA7U3d1Pi25gE6LMFsG/kA7Z9hPw/THvQANLXJv4frU + FwAAAYbrrwAfAAAEAwBIMEYCIQCZUf8y3yPDyIA/hfhvZ21ukC3zcdunoqVq+TQW + YksMpgIhALfmINPZJmrjy5T/zeHxCxHCHaBpRMIKGAej1JkgeknSAHUAdv+IPwq2 + +5VRwmHM9Ye6NLSkzbsp3GhCCp/mZ0xaOnQAAAGG668ATwAABAMARjBEAiBWGuOl + X3fLXWfP3ihTE9q/c5sco24KNW0Ij6NaK40hcgIgFKryWdWqqZRoI9LgeBqkzs2p + 8ivZEu2wLXX+RoyoCL4wCgYIKoZIzj0EAwMDaAAwZQIxAKcEoh9LUSQ2h/XcESEG + LxpGGAcssmrUXBDE0jJPSGgg1ypiE0ay+nYv3TIxVenpIQIweLQmI/ljlQtRBEEh + JdnlcMbdN5VOUqtwqd3jEVBgU6vyUmRltnZybBAMUiBpWX+t -----END CERTIFICATE----- CERT; $ca1 = <<<'CERT' -----BEGIN CERTIFICATE----- - MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh - MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 - d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD - QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT - MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg - U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB - ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83 - nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd - KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f - /ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX - kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0 - /RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C - AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY - aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6 - Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1 - oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD - QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v - d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh - xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB - CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl - 5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA - 8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC - 2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit - c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0 - j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz + MIIDajCCAu+gAwIBAgIQBBxdKC6zcQ5rcsLavSZxbzAKBggqhkjOPQQDAzBOMQsw + CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp + Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDQxNDAwMDAwMFoXDTMx + MDQxMzIzNTk1OVowVDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ + bmMuMSwwKgYDVQQDEyNEaWdpQ2VydCBHNSBUTFMgRUNDIFNIQTM4NCAyMDIxIENB + MTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLzRK0f/iJs+T+i9//yOWT++GUuwRjML + dbsA+9YQsrHFyayUZeqYRATordp1DcodGY/1DxRAwDDEi0cmkfHX08nLQ0ujF1Vh + dlBxYUPol2HLYjN3EzVAcDC8V5uiQc5zCqOCAYowggGGMBIGA1UdEwEB/wQIMAYB + Af8CAQAwHQYDVR0OBBYEFJtY3I2mZZjnvAb+GqQVoG/L5qmQMB8GA1UdIwQYMBaA + FMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAU + BggrBgEFBQcDAQYIKwYBBQUHAwIwegYIKwYBBQUHAQEEbjBsMCQGCCsGAQUFBzAB + hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRAYIKwYBBQUHMAKGOGh0dHA6Ly9j + YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRMU0VDQ1AzODRSb290RzUuY3J0 + MEYGA1UdHwQ/MD0wO6A5oDeGNWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdp + Q2VydFRMU0VDQ1AzODRSb290RzUuY3JsMD0GA1UdIAQ2MDQwCwYJYIZIAYb9bAIB + MAcGBWeBDAEBMAgGBmeBDAECATAIBgZngQwBAgIwCAYGZ4EMAQIDMAoGCCqGSM49 + BAMDA2kAMGYCMQDt1p2aebRUXBPN1FXg+V6oG+mRLdRC49k8dSxwRG77lsj1YqTO + IvZuhDckSAkMNGICMQD4lvGyMGMQirgiqAaMdybUTpcDTLtRQPKiGVZOoSaRtq8o + gRocsHZfwG69pfWn10Y= -----END CERTIFICATE----- CERT; $ca2 = <<<'CERT' -----BEGIN CERTIFICATE----- - MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh - MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 - d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD - QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT - MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j - b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG - 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB - CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 - nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt - 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P - T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 - gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO - BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR - TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw - DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr - hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg - 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF - PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls - YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk - CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= + MIIDIDCCAqagAwIBAgIQDdiPPdDfPycTMSudQiae5zAKBggqhkjOPQQDAzBhMQsw + CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu + ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe + Fw0yMjA5MjEwMDAwMDBaFw0zNzA5MjAyMzU5NTlaME4xCzAJBgNVBAYTAlVTMRcw + FQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEmMCQGA1UEAxMdRGlnaUNlcnQgVExTIEVD + QyBQMzg0IFJvb3QgRzUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATBRKHPEZdQmt4j + gjUHzdDLGJ3S8X93NU873ZRyUu3CO/js+ntrWCDsma7J/GizdbnbCezIE/VOxgod + ZjBMux9HCjxhEEIpfKUIDuAi6dM1aM6bY5+EtZlNWKCO9VTnlcmjggE0MIIBMDAP + BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTBUUVQWas+5yxa+iAiEgeAiHwRajAf + BgNVHSMEGDAWgBSz20ik+aHF2K42QcwRY2liKbxLxjAOBgNVHQ8BAf8EBAMCAYYw + dgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy + dC5jb20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E + aWdpQ2VydEdsb2JhbFJvb3RHMy5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov + L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEczLmNybDARBgNV + HSAECjAIMAYGBFUdIAAwCgYIKoZIzj0EAwMDaAAwZQIwWaC7MYlkl+PK+/jDHt/6 + +exBh3Dt+pwj3KFpgZBWvKWLBGZUyX9WNBtj1eNgfCtXAjEApDGlZlvWDpn5/Dqe + NzZ6X97ngPkW2Eygum0xfANTThtvuxA8KQr3/ME81/h/Tj9O -----END CERTIFICATE----- CERT; - $responseFactory = static function ($method, $url, $options) { - self::assertSame('http://ocsp.digicert.com/', $url); - - return new MockResponse($options['body'], ['response_headers' => ['content-type' => Ocsp::OCSP_RESPONSE_MEDIATYPE]]); - }; - $httpClient = new MockHttpClient($responseFactory); + $ca3 = <<<'CERT' + -----BEGIN CERTIFICATE----- + MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw + CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu + ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe + Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw + EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x + IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF + K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG + fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO + Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd + BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx + AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ + oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 + sycX + -----END CERTIFICATE----- + CERT; - $ocspProphecy = $this->prophesize(Ocsp::class); - $ocspProphecy->buildOcspRequestBodySingle(Argument::any())->willReturn('Revoked'); - $ocspProphecy->decodeOcspResponseSingle(Argument::any()) - ->willReturn( - OcspResponse::revoked( - new \DateTimeImmutable('now'), - '8130451905380357229031687250908825482', - $revokedOn = new \DateTimeImmutable('2020-01-29T14:12:14.000000+0000'), - OcspResponse::REVOCATIONREASON_PRIVILEGEWITHDRAWN - ) - ); - $ocsp = $ocspProphecy->reveal(); + $httpClient = HttpClient::create(); $this->certificateValidator = new OCSPValidator( httpClient: $httpClient, - ocsp: $ocsp, ); try { $this->certificateValidator->validateStatus($certContents, [ - 'DigiCert Global Root CA' => $ca2, - 'DigiCert SHA2 Secure Server CA' => $ca1, + 'DigiCert G5 TLS ECC SHA384 2021 CA1' => $ca1, + 'DigiCert TLS ECC P384 Root G5' => $ca2, + 'DigiCert Global Root G3' => $ca3, ]); self::fail('Exception was expected.'); } catch (CertificateIsRevoked $e) { self::assertEquals([ - 'revoked_on' => $revokedOn, - 'reason_code' => 'privilegeWithdrawn', - 'reason' => new TranslatableArgument('the certificate (public-key or attribute certificate) was revoked because a privilege contained within that certificate has been withdrawn.'), - 'serial' => '8130451905380357229031687250908825482', + 'revoked_on' => new \DateTimeImmutable('2023-03-16T19:37:43.000000+0000'), + 'reason_code' => 'unspecified', + 'reason' => new TranslatableArgument('unspecified (no specific reason was given).'), + 'serial' => '7459839413651464540545224973334900563', ], $e->getParameters()); } } From 940e8f740a434b53c57f662afaf054ec10e2f232 Mon Sep 17 00:00:00 2001 From: Sebastiaan Stok Date: Fri, 22 Dec 2023 20:20:55 +0100 Subject: [PATCH 2/3] Let OCSPValidator fail gracefully with missing deb When the HttpClient is not installed the OCSP fails gracefully now informing how this can be resolved --- src/OCSPValidator.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/OCSPValidator.php b/src/OCSPValidator.php index a02173e..a0d1ee0 100644 --- a/src/OCSPValidator.php +++ b/src/OCSPValidator.php @@ -52,6 +52,10 @@ public function __construct( X509DataExtractor $dataExtractor = null, Ocsp $ocsp = null ) { + if ($httpClient === null && ! class_exists(HttpClient::class)) { + throw new \LogicException(sprintf('The "%s" class requires a "%s" instance, or that the Symfony HttpClient is available. Try running "composer require symfony/http-client".', self::class, HttpClientInterface::class)); + } + $this->extractor = $dataExtractor ?? new X509DataExtractor(); $this->httpClient = $httpClient ?? HttpClient::create(); $this->logger = $logger ?? new NullLogger(); From f71a97a8f39f19aa38e24efbcb2dd61e1750c5fc Mon Sep 17 00:00:00 2001 From: Sebastiaan Stok Date: Fri, 22 Dec 2023 20:28:52 +0100 Subject: [PATCH 3/3] Fix wrong spelling in className While considered a BC break this class should not be catch-ed directly --- Resources/translations/validators+intl-icu.en.xliff | 5 +++++ src/CAResolverImpl.php | 4 ++-- .../{ToManyCAsProvided.php => TooManyCAsProvided.php} | 6 +++--- tests/CAResolverImplTest.php | 4 ++-- 4 files changed, 12 insertions(+), 7 deletions(-) rename src/Violation/{ToManyCAsProvided.php => TooManyCAsProvided.php} (69%) diff --git a/Resources/translations/validators+intl-icu.en.xliff b/Resources/translations/validators+intl-icu.en.xliff index ef8b4d5..33ce259 100644 --- a/Resources/translations/validators+intl-icu.en.xliff +++ b/Resources/translations/validators+intl-icu.en.xliff @@ -88,6 +88,11 @@ it is known or suspected that aspects of the AA validated in the attribute certificate have been compromised. it is known or suspected that aspects of the AA validated in the attribute certificate have been compromised. + + + Too many CAs were provided. A maximum of 4 is accepted. + Too many CAs were provided. A maximum of 4 is accepted. + diff --git a/src/CAResolverImpl.php b/src/CAResolverImpl.php index 4e36bae..e654f1c 100644 --- a/src/CAResolverImpl.php +++ b/src/CAResolverImpl.php @@ -14,7 +14,7 @@ namespace Rollerworks\Component\X509Validator; use Rollerworks\Component\X509Validator\Violation\MissingCAExtension; -use Rollerworks\Component\X509Validator\Violation\ToManyCAsProvided; +use Rollerworks\Component\X509Validator\Violation\TooManyCAsProvided; use Rollerworks\Component\X509Validator\Violation\UnableToResolveParent; class CAResolverImpl implements CAResolver @@ -36,7 +36,7 @@ public function resolve(string $certificate, array $caList): ?CA // Safety check to prevent DoS attacks // Normally only two parents are used, more than three is exceptional if (\count($caList) > 4) { - throw new ToManyCAsProvided(); + throw new TooManyCAsProvided(); } $certData = $this->extractor->extractRawData($certificate, '', true); diff --git a/src/Violation/ToManyCAsProvided.php b/src/Violation/TooManyCAsProvided.php similarity index 69% rename from src/Violation/ToManyCAsProvided.php rename to src/Violation/TooManyCAsProvided.php index b3f4eb9..facf366 100644 --- a/src/Violation/ToManyCAsProvided.php +++ b/src/Violation/TooManyCAsProvided.php @@ -15,15 +15,15 @@ use Rollerworks\Component\X509Validator\Violation; -final class ToManyCAsProvided extends Violation +final class TooManyCAsProvided extends Violation { public function __construct() { - parent::__construct('To many CAs were provided. A maximum of 3 is accepted.'); + parent::__construct('Too many CAs were provided. A maximum of 4 is accepted.'); } public function getTranslatorMsg(): string { - return 'tls.violation.to_many_ca_provided'; + return 'Too many CAs were provided. A maximum of 4 is accepted.'; } } diff --git a/tests/CAResolverImplTest.php b/tests/CAResolverImplTest.php index fc126ea..269004a 100644 --- a/tests/CAResolverImplTest.php +++ b/tests/CAResolverImplTest.php @@ -19,7 +19,7 @@ use Rollerworks\Component\X509Validator\CA; use Rollerworks\Component\X509Validator\CAResolverImpl as CAResolver; use Rollerworks\Component\X509Validator\Violation\MissingCAExtension; -use Rollerworks\Component\X509Validator\Violation\ToManyCAsProvided; +use Rollerworks\Component\X509Validator\Violation\TooManyCAsProvided; use Rollerworks\Component\X509Validator\Violation\UnableToResolveParent; use Rollerworks\Component\X509Validator\Violation\UnprocessablePEM; @@ -98,7 +98,7 @@ public function it_fails_with_to_many_cas_provided(): void { $resolver = new CAResolver(); - $this->expectException(ToManyCAsProvided::class); + $this->expectException(TooManyCAsProvided::class); $resolver->resolve( <<<'CERT'