From 4d4fa7d3b8f9a2e0219fbaf181b03182b6a57622 Mon Sep 17 00:00:00 2001 From: Sebastiaan Stok Date: Sun, 24 Dec 2023 15:14:57 +0100 Subject: [PATCH] Fix wrong translations And simplify revocation descriptions Remove PublicKeyMismatch as this redundant with PrivateKeyMismatch (was CertificateMismatch) --- .../translations/validators+intl-icu.en.xliff | 109 ++-- UPGRADE.md | 6 + composer.json | 1 + docs/index.md | 4 +- src/KeyValidator.php | 19 +- src/Violation.php | 2 +- src/Violation/CertificateHasExpired.php | 2 +- src/Violation/CertificateIsRevoked.php | 16 +- src/Violation/KeyBitsTooLow.php | 2 +- src/Violation/MissingCAExtension.php | 2 +- ...ateMismatch.php => PrivateKeyMismatch.php} | 2 +- src/Violation/PublicKeyMismatch.php | 29 - src/Violation/UnprocessableKey.php | 2 +- src/Violation/UnprocessablePEM.php | 8 +- src/Violation/UnsupportedDomain.php | 2 +- src/Violation/UnsupportedPurpose.php | 2 +- src/Violation/WeakSignatureAlgorithm.php | 2 +- tests/CAResolverImplTest.php | 586 ++++++++++-------- tests/CertificateValidatorTest.php | 18 + tests/KeyValidatorTest.php | 384 ++++++------ tests/OCSPValidatorTest.php | 27 +- tests/TranslatorAssertionTrait.php | 35 ++ 22 files changed, 687 insertions(+), 573 deletions(-) rename src/Violation/{CertificateMismatch.php => PrivateKeyMismatch.php} (93%) delete mode 100644 src/Violation/PublicKeyMismatch.php create mode 100644 tests/TranslatorAssertionTrait.php diff --git a/Resources/translations/validators+intl-icu.en.xliff b/Resources/translations/validators+intl-icu.en.xliff index 33ce259..ece166e 100644 --- a/Resources/translations/validators+intl-icu.en.xliff +++ b/Resources/translations/validators+intl-icu.en.xliff @@ -3,95 +3,102 @@ - Unable to process PEM X.509 data of private key "{name}". Only PEM encoded X.509 files are supported. - Unable to process PEM X.509 data of private key "{name}". Only PEM encoded X.509 files are supported. + Unable to process certificate "{name}". Only PEM encoded X.509 files are supported. + Unable to process certificate "{name}". Only PEM encoded X.509 files are supported. - The certificate public-key does not match with the private-key "public-key" data. - The certificate public-key does not match with the private-key "public-key" data. + Unable to process certificate. Only PEM encoded X.509 files are supported. + Unable to process certificate. Only PEM encoded X.509 files are supported. - The certificate does not match with the provided private-key. - The certificate does not match with the provided private-key. + Unable to process private key. Only PEM encoded X.509 files are supported. + Unable to process private key. Only PEM encoded X.509 files are supported. - This certificate was signed using the weak "{provided}" algorithm. Expected at least algorithm "{expected}".". - This certificate was signed using the weak "{provided}" algorithm. Expected at least algorithm "{expected}".". + The certificate does not match with the provided private-key. + The certificate does not match with the provided private-key. - The private-key bits-size {provided} is too low. Expected at least {expected} bits. - The private-key bits-size {provided} is too low. Expected at least {expected} bits. + The certificate was signed using the weak "{provided}" algorithm. Expected at least algorithm "{expected}".". + The certificate was signed using the weak "{provided}" algorithm. Expected at least algorithm "{expected}".". - The certificate with serial-number "{serial}" was marked as revoked on { revoked_on, date, short } with ({reason_code}) {reason}. - The certificate with serial-number "{serial}" was marked as revoked on { revoked_on, date, short } with ({reason_code}) {reason}. + The private-key bits-size {provided} is too low. Expected at least {expected} bits. + The private-key bits-size {provided} is too low. Expected at least {expected} bits. - The certificate with common-name "{common_name}" contains a CA extension. Expected a leaf certificate. - The certificate with common-name "{common_name}" contains a CA extension. Expected a leaf certificate. + The certificate with serial-number "{serial}" was marked as revoked on { revoked_on, date, short } with reason: ({reason_code}) {reason}. + The certificate with serial-number "{serial}" was marked as revoked on { revoked_on, date, short } with reason: ({reason_code}) {reason}. - This certificate has expired on { expired_on, date, short }. - This certificate has expired on { expired_on, date, short }. + The certificate with common-name "{common_name}" contains a CA extension. Expected a leaf certificate. + The certificate with common-name "{common_name}" contains a CA extension. Expected a leaf certificate. - This certificate should support host pattern "{required_pattern}". But only the following patterns are {supported} - This certificate should support host pattern "{required_pattern}". But only the following patterns are {supported} + Certificate with common-name "{common_name}" does not contain required CA extension. + Certificate with common-name "{common_name}" does not contain required CA extension. - This certificate does not support the {required_purpose} - This certificate does not support the {required_purpose} + The certificate has expired on { expired_on, date, short }. + The certificate has expired on { expired_on, date, short }. + The certificate should support host pattern "{required_pattern}". But only the following patterns are supported: {supported}. + The certificate should support host pattern "{required_pattern}". But only the following patterns are supported: {supported}. + + + The certificate does not support the purpose: {required_purpose}. + The certificate does not support the purpose: {required_purpose}. + + The certificate host "{provided}" contains an invalid global-wildcard pattern. The certificate host "{provided}" contains an invalid global-wildcard pattern. - + The certificate host "{provided}" contains an invalid public-suffix wildcard pattern "{suffix_pattern}". The certificate host "{provided}" contains an invalid public-suffix wildcard pattern "{suffix_pattern}". - + Unable to resolve the CA of certificate "{name}", issued by {parent}. Unable to resolve the CA of certificate "{name}", issued by {parent}. + + Too many CAs were provided. A maximum of 4 is accepted. + Too many CAs were provided. A maximum of 4 is accepted. + - - unspecified (no specific reason was given). - unspecified (no specific reason was given). - - - the private key associated with the certificate has been compromised. - the private key associated with the certificate has been compromised. + + no specific reason was given + no specific reason was given - - the CAs private key is has been compromised and is in the possession of an unauthorized individual. When a CAs private key is revoked, this results in all certificates issued by the CA that are signed using the private key associated with the revoked certificate being considered revoked. - the CAs private key is has been compromised and is in the possession of an unauthorized individual. When a CAs private key is revoked, this results in all certificates issued by the CA that are signed using the private key associated with the revoked certificate being considered revoked. + + the private key associated with the certificate has been compromised + the private key associated with the certificate has been compromised - - the user has terminated their relationship with the organization indicated in the Distinguished Name attribute of the certificate. This revocation code is typically used when an individual is terminated or has resigned from an organization. - the user has terminated their relationship with the organization indicated in the Distinguished Name attribute of the certificate. This revocation code is typically used when an individual is terminated or has resigned from an organization. + + the CA's private key is has been compromised and is in the possession of an unauthorized individual + the CA's private key is has been compromised and is in the possession of an unauthorized individual - - a replacement certificate has been issued to a user. - a replacement certificate has been issued to a user. + + the user has terminated their relationship with the organization indicated in the Distinguished Name attribute of the certificate + the user has terminated their relationship with the organization indicated in the Distinguished Name attribute of the certificate - - the CA is decommissioned, no longer to be used. - the CA is decommissioned, no longer to be used. + + a replacement certificate has been issued to a user + a replacement certificate has been issued to a user - - the certificate (public-key or attribute certificate) was revoked because a privilege contained within that certificate has been withdrawn. - the certificate (public-key or attribute certificate) was revoked because a privilege contained within that certificate has been withdrawn. + + the CA is decommissioned, no longer to be used + the CA is decommissioned, no longer to be used - - 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. + + the certificate (public-key or attribute certificate) was revoked because a privilege contained within that certificate has been withdrawn + the certificate (public-key or attribute certificate) was revoked because a privilege contained within that certificate has been withdrawn - - - Too many CAs were provided. A maximum of 4 is accepted. - Too many CAs were provided. A maximum of 4 is accepted. + + 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 diff --git a/UPGRADE.md b/UPGRADE.md index d8ffc62..3b6e67d 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,6 +1,12 @@ UPGRADE ======= + +## Upgrade FROM 0.2.1 to 0.2.2 + +* Translation ids have changed to fix some mismatches. +* The `PublicKeyMismatch` violation was removed. + ## Upgrade FROM 0.1.0 to 0.2.0 * The `CertificateValidator` now expects a `\Pdp\PublicSuffixList` instance diff --git a/composer.json b/composer.json index a3ea5c0..8a3e5e5 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,7 @@ "rollerscapes/standards": "^1.0", "rollerworks/pdb-symfony-bridge": "^1.0", "symfony/clock": "^6.3", + "symfony/config": "^6.4 || ^7.0", "symfony/error-handler": "^6.3", "symfony/http-client": "^6.3", "symfony/phpunit-bridge": "^6.3 || ^7.0", diff --git a/docs/index.md b/docs/index.md index 45fe681..41702da 100644 --- a/docs/index.md +++ b/docs/index.md @@ -129,12 +129,12 @@ final class EmailFieldRequired extends Violation { public function __construct() { - parent::__construct('This certificate should contains an emails extension.'); + parent::__construct('The certificate should contains an emails extension.'); } public function getTranslatorMsg(): string { - return 'This certificate should contains an emails extension.'; + return 'The certificate should contains an emails extension.'; } } diff --git a/src/KeyValidator.php b/src/KeyValidator.php index 7b6a713..99b81a6 100644 --- a/src/KeyValidator.php +++ b/src/KeyValidator.php @@ -14,9 +14,8 @@ namespace Rollerworks\Component\X509Validator; use ParagonIE\HiddenString\HiddenString; -use Rollerworks\Component\X509Validator\Violation\CertificateMismatch; use Rollerworks\Component\X509Validator\Violation\KeyBitsTooLow; -use Rollerworks\Component\X509Validator\Violation\PublicKeyMismatch; +use Rollerworks\Component\X509Validator\Violation\PrivateKeyMismatch; use Rollerworks\Component\X509Validator\Violation\UnprocessableKey; use Rollerworks\Component\X509Validator\Violation\UnprocessablePEM; @@ -31,14 +30,14 @@ class KeyValidator * matches with the public key of the certificate. And Then performs * an additional check to ensure the key was not tempered with. * - * @param HiddenString|string $privateKey Private-key as PEM X509. Use HiddenString to prevent leaking - * sensitive information + * @param HiddenString|string $privateKey Private-key as PEM X509. + * Use HiddenString to prevent leaking sensitive information * @param string $certificate Certificate as PEM X509 format string * - * @throws UnprocessablePEM when the data cannot be parsed or processed - * @throws PublicKeyMismatch when the public-keys don't match - * @throws CertificateMismatch when the private doesn't match the certificate - * @throws KeyBitsTooLow when the private bits count is less than $minimumBitCount + * @throws UnprocessablePEM when the certificate cannot be parsed or processed + * @throws UnprocessableKey when the private-key cannot be parsed or processed + * @throws PrivateKeyMismatch when the private doesn't match the certificate + * @throws KeyBitsTooLow when the private bits count is less than $minimumBitCount */ public function validate(HiddenString | string $privateKey, string $certificate, int $minimumBitCount = self::MINIMUM_BIT_COUNT): void { @@ -64,7 +63,7 @@ public function validate(HiddenString | string $privateKey, string $certificate, } if (! @openssl_x509_check_private_key($certR, $privateR)) { - throw new PublicKeyMismatch(); + throw new PrivateKeyMismatch(); } // Note: technically it's rather difficult to replace the public-key @@ -81,7 +80,7 @@ public function validate(HiddenString | string $privateKey, string $certificate, } if (! @openssl_private_decrypt($encrypted, $decrypted, $privateR, \OPENSSL_PKCS1_OAEP_PADDING) || $decrypted !== $original) { - throw new CertificateMismatch(); + throw new PrivateKeyMismatch(); } $details = @openssl_pkey_get_details($privateR); diff --git a/src/Violation.php b/src/Violation.php index 317dadf..2c530dd 100644 --- a/src/Violation.php +++ b/src/Violation.php @@ -37,6 +37,6 @@ public function __debugInfo(): array public function trans(TranslatorInterface $translator, string $locale = null): string { - return $translator->trans($this->getMessage(), $this->getParameters(), 'validators', $locale); + return $translator->trans($this->getTranslatorMsg(), $this->getParameters(), 'validators', $locale); } } diff --git a/src/Violation/CertificateHasExpired.php b/src/Violation/CertificateHasExpired.php index 8beabc5..7531aaa 100644 --- a/src/Violation/CertificateHasExpired.php +++ b/src/Violation/CertificateHasExpired.php @@ -28,7 +28,7 @@ public function __construct(\DateTimeInterface $expiredOn) public function getTranslatorMsg(): string { - return 'This certificate has expired on { expired_on, date, short }.'; + return 'The certificate has expired on { expired_on, date, short }.'; } public function getParameters(): array diff --git a/src/Violation/CertificateIsRevoked.php b/src/Violation/CertificateIsRevoked.php index ae10ef7..8617006 100644 --- a/src/Violation/CertificateIsRevoked.php +++ b/src/Violation/CertificateIsRevoked.php @@ -47,16 +47,16 @@ final class CertificateIsRevoked extends Violation ]; private const TRANSLATOR_ID = [ - 'unspecified' => 'unspecified (no specific reason was given).', - 'keyCompromise' => 'the private key associated with the certificate has been compromised.', - 'cACompromise' => 'the CA\'s private key is has been compromised and is in the possession of an unauthorized individual. When a CA\'s private key is revoked, this results in all certificates issued by the CA that are signed using the private key associated with the revoked certificate being considered revoked.', - 'affiliationChanged' => 'the user has terminated their relationship with the organization indicated in the Distinguished Name attribute of the certificate. This revocation code is typically used when an individual is terminated or has resigned from an organization.', - 'superseded' => 'a replacement certificate has been issued to a user.', - 'cessationOfOperation' => 'the CA is decommissioned, no longer to be used.', + 'unspecified' => 'no specific reason was given', + 'keyCompromise' => 'the private key associated with the certificate has been compromised', + 'cACompromise' => 'the CA\'s private key is has been compromised and is in the possession of an unauthorized individual', + 'affiliationChanged' => 'the user has terminated their relationship with the organization indicated in the Distinguished Name attribute of the certificate', + 'superseded' => 'a replacement certificate has been issued to a user', + 'cessationOfOperation' => 'the CA is decommissioned, no longer to be used', 'certificateHold' => 'the certificate is currently on hold, try again later', 'removeFromCRL' => 'certificate revocation is removed', // This might possible not be an error - 'privilegeWithdrawn' => 'the certificate (public-key or attribute certificate) was revoked because a privilege contained within that certificate has been withdrawn.', - 'aACompromise' => 'it is known or suspected that aspects of the AA validated in the attribute certificate have been compromised.', + 'privilegeWithdrawn' => 'the certificate (public-key or attribute certificate) was revoked because a privilege contained within that certificate has been withdrawn', + 'aACompromise' => 'it is known or suspected that aspects of the AA validated in the attribute certificate have been compromised', ]; private readonly ?\DateTimeInterface $revokedOn; diff --git a/src/Violation/KeyBitsTooLow.php b/src/Violation/KeyBitsTooLow.php index 80cf34f..368853c 100644 --- a/src/Violation/KeyBitsTooLow.php +++ b/src/Violation/KeyBitsTooLow.php @@ -22,7 +22,7 @@ final class KeyBitsTooLow extends Violation public function __construct(int $expected, int $provided) { - parent::__construct(sprintf('Private-key bits size %d lower than required %d.', $provided, $expected)); + parent::__construct(sprintf('Private-key bits-size %d is lower than expected %d.', $provided, $expected)); $this->expected = $expected; $this->provided = $provided; diff --git a/src/Violation/MissingCAExtension.php b/src/Violation/MissingCAExtension.php index 2f15c4f..5384021 100644 --- a/src/Violation/MissingCAExtension.php +++ b/src/Violation/MissingCAExtension.php @@ -24,7 +24,7 @@ public function __construct(private readonly string $name) public function getTranslatorMsg(): string { - return 'tls.violation.certificate_is_ca'; + return 'Certificate with common-name "{common_name}" does not contain required CA extension.'; } public function getParameters(): array diff --git a/src/Violation/CertificateMismatch.php b/src/Violation/PrivateKeyMismatch.php similarity index 93% rename from src/Violation/CertificateMismatch.php rename to src/Violation/PrivateKeyMismatch.php index 3ca08fe..002010c 100644 --- a/src/Violation/CertificateMismatch.php +++ b/src/Violation/PrivateKeyMismatch.php @@ -15,7 +15,7 @@ use Rollerworks\Component\X509Validator\Violation; -final class CertificateMismatch extends Violation +final class PrivateKeyMismatch extends Violation { public function __construct() { diff --git a/src/Violation/PublicKeyMismatch.php b/src/Violation/PublicKeyMismatch.php deleted file mode 100644 index 2547224..0000000 --- a/src/Violation/PublicKeyMismatch.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -namespace Rollerworks\Component\X509Validator\Violation; - -use Rollerworks\Component\X509Validator\Violation; - -final class PublicKeyMismatch extends Violation -{ - public function __construct() - { - parent::__construct('The public-key of the certificate does not match with the provided private-key.'); - } - - public function getTranslatorMsg(): string - { - return 'The certificate public-key does not match with the private-key "public-key" data.'; - } -} diff --git a/src/Violation/UnprocessableKey.php b/src/Violation/UnprocessableKey.php index 636d1c6..a718725 100644 --- a/src/Violation/UnprocessableKey.php +++ b/src/Violation/UnprocessableKey.php @@ -24,6 +24,6 @@ public function __construct(string $message = '') public function getTranslatorMsg(): string { - return 'Unable to process PEM X.509 data of private key "{name}". Only PEM encoded X.509 files are supported.'; + return 'Unable to process private key. Only PEM encoded X.509 files are supported.'; } } diff --git a/src/Violation/UnprocessablePEM.php b/src/Violation/UnprocessablePEM.php index ee6ca16..cad86b4 100644 --- a/src/Violation/UnprocessablePEM.php +++ b/src/Violation/UnprocessablePEM.php @@ -16,7 +16,7 @@ use Rollerworks\Component\X509Validator\Violation; /** - * This exception class is used for when the data cannot be processed or parse. + * This exception class is used for when the data cannot be processed or parsed. */ final class UnprocessablePEM extends Violation { @@ -28,7 +28,11 @@ public function __construct(private readonly string $certName, string $contents public function getTranslatorMsg(): string { - return 'Unable to process PEM X.509 data of certificate "{name}". Only PEM encoded X.509 files are supported.'; + if ($this->certName === '') { + return 'Unable to process certificate. Only PEM encoded X.509 files are supported.'; + } + + return 'Unable to process certificate "{name}". Only PEM encoded X.509 files are supported.'; } public function getParameters(): array diff --git a/src/Violation/UnsupportedDomain.php b/src/Violation/UnsupportedDomain.php index 42033e3..1ba5018 100644 --- a/src/Violation/UnsupportedDomain.php +++ b/src/Violation/UnsupportedDomain.php @@ -31,7 +31,7 @@ public function __construct(string $requiredPattern, string ...$supported) public function getTranslatorMsg(): string { - return 'This certificate should support host pattern "{required_pattern}". But only the following patterns are supported: {supported}'; + return 'The certificate should support host pattern "{required_pattern}". But only the following patterns are supported: {supported}.'; } public function getParameters(): array diff --git a/src/Violation/UnsupportedPurpose.php b/src/Violation/UnsupportedPurpose.php index dfd893c..c856bfd 100644 --- a/src/Violation/UnsupportedPurpose.php +++ b/src/Violation/UnsupportedPurpose.php @@ -29,7 +29,7 @@ public function __construct(string $requiredPurpose) public function getTranslatorMsg(): string { - return 'This certificate does not support the purpose: {required_purpose}'; + return 'The certificate does not support the purpose: {required_purpose}.'; } public function getParameters(): array diff --git a/src/Violation/WeakSignatureAlgorithm.php b/src/Violation/WeakSignatureAlgorithm.php index 0c6c13c..5cb1119 100644 --- a/src/Violation/WeakSignatureAlgorithm.php +++ b/src/Violation/WeakSignatureAlgorithm.php @@ -30,7 +30,7 @@ public function __construct(string $expected, string $provided) public function getTranslatorMsg(): string { - return 'This certificate was signed using the weak "{provided}" algorithm. Expected at least algorithm "{expected}".".'; + return 'The certificate was signed using the weak "{provided}" algorithm. Expected at least algorithm "{expected}".".'; } public function getParameters(): array diff --git a/tests/CAResolverImplTest.php b/tests/CAResolverImplTest.php index 269004a..c07796d 100644 --- a/tests/CAResolverImplTest.php +++ b/tests/CAResolverImplTest.php @@ -29,68 +29,74 @@ final class CAResolverImplTest extends TestCase { use ProphecyTrait; + use TranslatorAssertionTrait; #[Test] public function it_fails_with_incomplete_ca_list(): void { $resolver = new CAResolver(); - $this->expectException(UnableToResolveParent::class); - - $resolver->resolve( - <<<'CERT' - -----BEGIN CERTIFICATE----- - MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS - b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH - DAlSb3R0ZXJkYW0xCzAJBgNVBAYTAk5MMB4XDTE0MDcyNzEzMDIzM1oXDTE4MDcy - NjEzMDIzM1owWzEhMB8GA1UEAwwYYm9wLmRldi5yb2xsZXJzY2FwZXMubmV0MRUw - EwYDVQQKDAxSb2xsZXJzY2FwZXMxEjAQBgNVBAcMCVJvdHRlcmRhbTELMAkGA1UE - BhMCTkwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFN7758InBPIIE - Q/VoYrj/poR1bGEcupAB+Q68R2C5ac5EGQMwaODCphP1RetLGHJE+4hss9GzJb56 - LfLSKy500Zk6R50zUXNCJwvkMvODHTMDy0xORg7tMbe3kLnHH/lbhmeWmXt5qDxa - S2jx5A2pKGmoLS8smYFlPRZ0yiK8Ugy5kDWCEFA31TIsGKcofOWcr+vfJ7HltXav - h1VFZ2nzJC8xKaoFQO4uake225CZQ+W4yhIxu5beY/FXlh2PIZqd1rQhQLuV5gK4 - zGkjNkN6DVJ+7xwnYJ7yeXKlovwMOEJQG1LHnr16gFRRcFeVUHPZkW47QGOYh60n - rG8/8/kLAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAKLWz2F2bJyhTlHxAORbdugm - esBbPxlhkCitdXp7uAkQh+0HeJ+jFb+CA0blmGyY3j15t54WV9ySMV8tQRSk5sXl - VVaJ4AF0uIvT5gbOvL8Vr2ZNiWp2S0Nqx28JVP/KNCAI3PBIWnDcQOON3gHQQi9O - qmL+vAuODEQ2UvgCd2GgFPqsu79Y1PRbqRIwqNiFasHt9pQNlpzRM6AjtUMldShG - rpz1WIZIIZuH+TC/iqD7UlSoLxJbe79a6dbBNw7bnWlo+HDl8YfmY6Ks3O6MCbYn - qVBRc3K9ywcUYPJNVuUazdXuY6FSiGB1iOLxRHppQapmWK5GdtQFXW3GlkXFYf4= - -----END CERTIFICATE----- - CERT, - [ - 'ca1' => <<<'CERT' + try { + $resolver->resolve( + <<<'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 + MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS + b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH + DAlSb3R0ZXJkYW0xCzAJBgNVBAYTAk5MMB4XDTE0MDcyNzEzMDIzM1oXDTE4MDcy + NjEzMDIzM1owWzEhMB8GA1UEAwwYYm9wLmRldi5yb2xsZXJzY2FwZXMubmV0MRUw + EwYDVQQKDAxSb2xsZXJzY2FwZXMxEjAQBgNVBAcMCVJvdHRlcmRhbTELMAkGA1UE + BhMCTkwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFN7758InBPIIE + Q/VoYrj/poR1bGEcupAB+Q68R2C5ac5EGQMwaODCphP1RetLGHJE+4hss9GzJb56 + LfLSKy500Zk6R50zUXNCJwvkMvODHTMDy0xORg7tMbe3kLnHH/lbhmeWmXt5qDxa + S2jx5A2pKGmoLS8smYFlPRZ0yiK8Ugy5kDWCEFA31TIsGKcofOWcr+vfJ7HltXav + h1VFZ2nzJC8xKaoFQO4uake225CZQ+W4yhIxu5beY/FXlh2PIZqd1rQhQLuV5gK4 + zGkjNkN6DVJ+7xwnYJ7yeXKlovwMOEJQG1LHnr16gFRRcFeVUHPZkW47QGOYh60n + rG8/8/kLAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAKLWz2F2bJyhTlHxAORbdugm + esBbPxlhkCitdXp7uAkQh+0HeJ+jFb+CA0blmGyY3j15t54WV9ySMV8tQRSk5sXl + VVaJ4AF0uIvT5gbOvL8Vr2ZNiWp2S0Nqx28JVP/KNCAI3PBIWnDcQOON3gHQQi9O + qmL+vAuODEQ2UvgCd2GgFPqsu79Y1PRbqRIwqNiFasHt9pQNlpzRM6AjtUMldShG + rpz1WIZIIZuH+TC/iqD7UlSoLxJbe79a6dbBNw7bnWlo+HDl8YfmY6Ks3O6MCbYn + qVBRc3K9ywcUYPJNVuUazdXuY6FSiGB1iOLxRHppQapmWK5GdtQFXW3GlkXFYf4= -----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 + -----END CERTIFICATE----- + CERT, + ] + ); + + self::fail('Exception was expected.'); + } catch (UnableToResolveParent $e) { + self::assertSame(['name' => 'bop.dev.rollerscapes.net', 'parent' => 'Rollerscapes CAv3'], $e->getParameters()); + self::assertTranslationEquals('Unable to resolve the CA of certificate "bop.dev.rollerscapes.net", issued by Rollerscapes CAv3.', $e); + } } #[Test] @@ -98,197 +104,253 @@ public function it_fails_with_to_many_cas_provided(): void { $resolver = new CAResolver(); - $this->expectException(TooManyCAsProvided::class); - - $resolver->resolve( - <<<'CERT' - -----BEGIN CERTIFICATE----- - MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS - b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH - DAlSb3R0ZXJkYW0xCzAJBgNVBAYTAk5MMB4XDTE0MDcyNzEzMDIzM1oXDTE4MDcy - NjEzMDIzM1owWzEhMB8GA1UEAwwYYm9wLmRldi5yb2xsZXJzY2FwZXMubmV0MRUw - EwYDVQQKDAxSb2xsZXJzY2FwZXMxEjAQBgNVBAcMCVJvdHRlcmRhbTELMAkGA1UE - BhMCTkwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFN7758InBPIIE - Q/VoYrj/poR1bGEcupAB+Q68R2C5ac5EGQMwaODCphP1RetLGHJE+4hss9GzJb56 - LfLSKy500Zk6R50zUXNCJwvkMvODHTMDy0xORg7tMbe3kLnHH/lbhmeWmXt5qDxa - S2jx5A2pKGmoLS8smYFlPRZ0yiK8Ugy5kDWCEFA31TIsGKcofOWcr+vfJ7HltXav - h1VFZ2nzJC8xKaoFQO4uake225CZQ+W4yhIxu5beY/FXlh2PIZqd1rQhQLuV5gK4 - zGkjNkN6DVJ+7xwnYJ7yeXKlovwMOEJQG1LHnr16gFRRcFeVUHPZkW47QGOYh60n - rG8/8/kLAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAKLWz2F2bJyhTlHxAORbdugm - esBbPxlhkCitdXp7uAkQh+0HeJ+jFb+CA0blmGyY3j15t54WV9ySMV8tQRSk5sXl - VVaJ4AF0uIvT5gbOvL8Vr2ZNiWp2S0Nqx28JVP/KNCAI3PBIWnDcQOON3gHQQi9O - qmL+vAuODEQ2UvgCd2GgFPqsu79Y1PRbqRIwqNiFasHt9pQNlpzRM6AjtUMldShG - rpz1WIZIIZuH+TC/iqD7UlSoLxJbe79a6dbBNw7bnWlo+HDl8YfmY6Ks3O6MCbYn - qVBRc3K9ywcUYPJNVuUazdXuY6FSiGB1iOLxRHppQapmWK5GdtQFXW3GlkXFYf4= - -----END CERTIFICATE----- - CERT, - [ - 'ca1' => <<<'CERT' + try { + $resolver->resolve( + <<<'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 + MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS + b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH + DAlSb3R0ZXJkYW0xCzAJBgNVBAYTAk5MMB4XDTE0MDcyNzEzMDIzM1oXDTE4MDcy + NjEzMDIzM1owWzEhMB8GA1UEAwwYYm9wLmRldi5yb2xsZXJzY2FwZXMubmV0MRUw + EwYDVQQKDAxSb2xsZXJzY2FwZXMxEjAQBgNVBAcMCVJvdHRlcmRhbTELMAkGA1UE + BhMCTkwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFN7758InBPIIE + Q/VoYrj/poR1bGEcupAB+Q68R2C5ac5EGQMwaODCphP1RetLGHJE+4hss9GzJb56 + LfLSKy500Zk6R50zUXNCJwvkMvODHTMDy0xORg7tMbe3kLnHH/lbhmeWmXt5qDxa + S2jx5A2pKGmoLS8smYFlPRZ0yiK8Ugy5kDWCEFA31TIsGKcofOWcr+vfJ7HltXav + h1VFZ2nzJC8xKaoFQO4uake225CZQ+W4yhIxu5beY/FXlh2PIZqd1rQhQLuV5gK4 + zGkjNkN6DVJ+7xwnYJ7yeXKlovwMOEJQG1LHnr16gFRRcFeVUHPZkW47QGOYh60n + rG8/8/kLAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAKLWz2F2bJyhTlHxAORbdugm + esBbPxlhkCitdXp7uAkQh+0HeJ+jFb+CA0blmGyY3j15t54WV9ySMV8tQRSk5sXl + VVaJ4AF0uIvT5gbOvL8Vr2ZNiWp2S0Nqx28JVP/KNCAI3PBIWnDcQOON3gHQQi9O + qmL+vAuODEQ2UvgCd2GgFPqsu79Y1PRbqRIwqNiFasHt9pQNlpzRM6AjtUMldShG + rpz1WIZIIZuH+TC/iqD7UlSoLxJbe79a6dbBNw7bnWlo+HDl8YfmY6Ks3O6MCbYn + qVBRc3K9ywcUYPJNVuUazdXuY6FSiGB1iOLxRHppQapmWK5GdtQFXW3GlkXFYf4= -----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 + -----END CERTIFICATE----- + CERT, - 'ca2' => <<<'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, - 'ca3' => <<<'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, - 'ca4' => <<<'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, - 'ca45' => <<<'CERT' + 'ca2' => <<<'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, + 'ca3' => <<<'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, + 'ca4' => <<<'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, + '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, + ] + ); + + self::fail('Exception was expected.'); + } catch (TooManyCAsProvided $e) { + self::assertTranslationEquals('Too many CAs were provided. A maximum of 4 is accepted.', $e); + } + } + + #[Test] + public function it_fails_with_invalid_pem(): void + { + $resolver = new CAResolver(); + + try { + $resolver->resolve( + <<<'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 + MIIDKzCCAhMCCQDZHE666I+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS + b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH -----END CERTIFICATE----- CERT, - ] - ); + [] + ); + + self::fail('Exception was expected.'); + } catch (UnprocessablePEM $e) { + self::assertSame(['name' => ''], $e->getParameters()); + + self::assertTranslationEquals('Unable to process certificate. Only PEM encoded X.509 files are supported.', $e); + } } #[Test] - public function it_fails_with_invalid_pem(): void + public function it_fails_with_invalid_ca_pem(): void { $resolver = new CAResolver(); - $this->expectException(UnprocessablePEM::class); + try { + $resolver->resolve( + <<<'CERT' + -----BEGIN CERTIFICATE----- + MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS + b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH + DAlSb3R0ZXJkYW0xCzAJBgNVBAYTAk5MMB4XDTE0MDcyNzEzMDIzM1oXDTE4MDcy + NjEzMDIzM1owWzEhMB8GA1UEAwwYYm9wLmRldi5yb2xsZXJzY2FwZXMubmV0MRUw + EwYDVQQKDAxSb2xsZXJzY2FwZXMxEjAQBgNVBAcMCVJvdHRlcmRhbTELMAkGA1UE + BhMCTkwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFN7758InBPIIE + Q/VoYrj/poR1bGEcupAB+Q68R2C5ac5EGQMwaODCphP1RetLGHJE+4hss9GzJb56 + LfLSKy500Zk6R50zUXNCJwvkMvODHTMDy0xORg7tMbe3kLnHH/lbhmeWmXt5qDxa + S2jx5A2pKGmoLS8smYFlPRZ0yiK8Ugy5kDWCEFA31TIsGKcofOWcr+vfJ7HltXav + h1VFZ2nzJC8xKaoFQO4uake225CZQ+W4yhIxu5beY/FXlh2PIZqd1rQhQLuV5gK4 + zGkjNkN6DVJ+7xwnYJ7yeXKlovwMOEJQG1LHnr16gFRRcFeVUHPZkW47QGOYh60n + rG8/8/kLAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAKLWz2F2bJyhTlHxAORbdugm + esBbPxlhkCitdXp7uAkQh+0HeJ+jFb+CA0blmGyY3j15t54WV9ySMV8tQRSk5sXl + VVaJ4AF0uIvT5gbOvL8Vr2ZNiWp2S0Nqx28JVP/KNCAI3PBIWnDcQOON3gHQQi9O + qmL+vAuODEQ2UvgCd2GgFPqsu79Y1PRbqRIwqNiFasHt9pQNlpzRM6AjtUMldShG + rpz1WIZIIZuH+TC/iqD7UlSoLxJbe79a6dbBNw7bnWlo+HDl8YfmY6Ks3O6MCbYn + qVBRc3K9ywcUYPJNVuUazdXuY6FSiGB1iOLxRHppQapmWK5GdtQFXW3GlkXFYf4= + -----END CERTIFICATE----- + CERT, + [ + 'CA 1' => <<<'CERT' + -----BEGIN CERTIFICATE----- + MIIDKzCCAhMCCQDZHE666I+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS + b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH + -----END CERTIFICATE----- + CERT, + ] + ); - $resolver->resolve( - <<<'CERT' - -----BEGIN CERTIFICATE----- - MIIDKzCCAhMCCQDZHE666I+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS - b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH - -----END CERTIFICATE----- - CERT, - [] - ); + self::fail('Exception was expected.'); + } catch (UnprocessablePEM $e) { + self::assertSame(['name' => 'CA 1'], $e->getParameters()); + + self::assertTranslationEquals('Unable to process certificate "CA 1". Only PEM encoded X.509 files are supported.', $e); + } } #[Test] @@ -296,36 +358,42 @@ public function it_fails_with_invalid_ca(): void { $resolver = new CAResolver(); - $this->expectException(MissingCAExtension::class); + try { + // Note. This works because validating a certificate signature against itself is always valid + // Even if signed by a CA. Which is why we always check if there is a parent. + $resolver->resolve( + $cert = <<<'CERT' + -----BEGIN CERTIFICATE----- + MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS + b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH + DAlSb3R0ZXJkYW0xCzAJBgNVBAYTAk5MMB4XDTE0MDcyNzEzMDIzM1oXDTE4MDcy + NjEzMDIzM1owWzEhMB8GA1UEAwwYYm9wLmRldi5yb2xsZXJzY2FwZXMubmV0MRUw + EwYDVQQKDAxSb2xsZXJzY2FwZXMxEjAQBgNVBAcMCVJvdHRlcmRhbTELMAkGA1UE + BhMCTkwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFN7758InBPIIE + Q/VoYrj/poR1bGEcupAB+Q68R2C5ac5EGQMwaODCphP1RetLGHJE+4hss9GzJb56 + LfLSKy500Zk6R50zUXNCJwvkMvODHTMDy0xORg7tMbe3kLnHH/lbhmeWmXt5qDxa + S2jx5A2pKGmoLS8smYFlPRZ0yiK8Ugy5kDWCEFA31TIsGKcofOWcr+vfJ7HltXav + h1VFZ2nzJC8xKaoFQO4uake225CZQ+W4yhIxu5beY/FXlh2PIZqd1rQhQLuV5gK4 + zGkjNkN6DVJ+7xwnYJ7yeXKlovwMOEJQG1LHnr16gFRRcFeVUHPZkW47QGOYh60n + rG8/8/kLAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAKLWz2F2bJyhTlHxAORbdugm + esBbPxlhkCitdXp7uAkQh+0HeJ+jFb+CA0blmGyY3j15t54WV9ySMV8tQRSk5sXl + VVaJ4AF0uIvT5gbOvL8Vr2ZNiWp2S0Nqx28JVP/KNCAI3PBIWnDcQOON3gHQQi9O + qmL+vAuODEQ2UvgCd2GgFPqsu79Y1PRbqRIwqNiFasHt9pQNlpzRM6AjtUMldShG + rpz1WIZIIZuH+TC/iqD7UlSoLxJbe79a6dbBNw7bnWlo+HDl8YfmY6Ks3O6MCbYn + qVBRc3K9ywcUYPJNVuUazdXuY6FSiGB1iOLxRHppQapmWK5GdtQFXW3GlkXFYf4= + -----END CERTIFICATE----- + CERT, + [ + 'ca1' => $cert, + ] + ); - // Note. This works because validating a certificate signature against itself is always valid - // Even if signed by a CA. Which is why we always check if there is a parent. - $resolver->resolve( - $cert = <<<'CERT' - -----BEGIN CERTIFICATE----- - MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS - b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH - DAlSb3R0ZXJkYW0xCzAJBgNVBAYTAk5MMB4XDTE0MDcyNzEzMDIzM1oXDTE4MDcy - NjEzMDIzM1owWzEhMB8GA1UEAwwYYm9wLmRldi5yb2xsZXJzY2FwZXMubmV0MRUw - EwYDVQQKDAxSb2xsZXJzY2FwZXMxEjAQBgNVBAcMCVJvdHRlcmRhbTELMAkGA1UE - BhMCTkwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFN7758InBPIIE - Q/VoYrj/poR1bGEcupAB+Q68R2C5ac5EGQMwaODCphP1RetLGHJE+4hss9GzJb56 - LfLSKy500Zk6R50zUXNCJwvkMvODHTMDy0xORg7tMbe3kLnHH/lbhmeWmXt5qDxa - S2jx5A2pKGmoLS8smYFlPRZ0yiK8Ugy5kDWCEFA31TIsGKcofOWcr+vfJ7HltXav - h1VFZ2nzJC8xKaoFQO4uake225CZQ+W4yhIxu5beY/FXlh2PIZqd1rQhQLuV5gK4 - zGkjNkN6DVJ+7xwnYJ7yeXKlovwMOEJQG1LHnr16gFRRcFeVUHPZkW47QGOYh60n - rG8/8/kLAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAKLWz2F2bJyhTlHxAORbdugm - esBbPxlhkCitdXp7uAkQh+0HeJ+jFb+CA0blmGyY3j15t54WV9ySMV8tQRSk5sXl - VVaJ4AF0uIvT5gbOvL8Vr2ZNiWp2S0Nqx28JVP/KNCAI3PBIWnDcQOON3gHQQi9O - qmL+vAuODEQ2UvgCd2GgFPqsu79Y1PRbqRIwqNiFasHt9pQNlpzRM6AjtUMldShG - rpz1WIZIIZuH+TC/iqD7UlSoLxJbe79a6dbBNw7bnWlo+HDl8YfmY6Ks3O6MCbYn - qVBRc3K9ywcUYPJNVuUazdXuY6FSiGB1iOLxRHppQapmWK5GdtQFXW3GlkXFYf4= - -----END CERTIFICATE----- - CERT, - [ - 'ca1' => $cert, - ] - ); + self::fail('Exception was expected.'); + } catch (MissingCAExtension $e) { + self::assertSame(['common_name' => 'bop.dev.rollerscapes.net'], $e->getParameters()); + + self::assertTranslationEquals('Certificate with common-name "bop.dev.rollerscapes.net" does not contain required CA extension.', $e); + } } #[Test] diff --git a/tests/CertificateValidatorTest.php b/tests/CertificateValidatorTest.php index 511d5f6..cc482e0 100644 --- a/tests/CertificateValidatorTest.php +++ b/tests/CertificateValidatorTest.php @@ -36,6 +36,8 @@ */ final class CertificateValidatorTest extends TestCase { + use TranslatorAssertionTrait; + private ClockInterface $clock; private CertificateValidator $certificateValidator; private PublicSuffixList $publicSuffixList; @@ -76,6 +78,7 @@ public function validate_certificate_is_actually_readable(): void } catch (UnprocessablePEM $e) { self::assertSame(['name' => ''], $e->getParameters()); self::assertSame($certContents, $e->getPrevious()?->getPrevious()?->getMessage()); + self::assertTranslationEquals('Unable to process certificate. Only PEM encoded X.509 files are supported.', $e); } } @@ -135,6 +138,7 @@ public function validate_certificate_is_expired(): void self::fail('Exception was expected.'); } catch (CertificateHasExpired $e) { self::assertEquals(['expired_on' => new \DateTimeImmutable('2018-07-26T13:02:33.000000+0000')], $e->getParameters()); + self::assertTranslationEquals('The certificate has expired on 7/26/18.', $e); } } @@ -159,6 +163,12 @@ public function validate_certificate_host_contains_global_wildcard(array $domain 'provided' => $provided, 'suffix_pattern' => $suffixPattern, ], $e->getParameters()); + + if ($provided === '*') { + self::assertTranslationEquals('The certificate host "*" contains an invalid global-wildcard pattern.', $e); + } else { + self::assertTranslationEquals(sprintf('The certificate host "%s" contains an invalid public-suffix wildcard pattern "%s".', $provided, $suffixPattern), $e); + } } } @@ -275,6 +285,8 @@ public function validate_certificate_signature_algorithm(): void self::fail('Exception was expected.'); } catch (WeakSignatureAlgorithm $e) { + self::assertTranslationEquals('The certificate was signed using the weak "sha1WithRSAEncryption" algorithm. Expected at least algorithm "SHA256".".', $e); + self::assertSame([ 'expected' => 'SHA256', 'provided' => 'sha1WithRSAEncryption', @@ -297,6 +309,8 @@ public function validate_certificate_data_is_readable(): void self::fail('Exception was expected.'); } catch (UnprocessablePEM $e) { + self::assertTranslationEquals('Unable to process certificate. Only PEM encoded X.509 files are supported.', $e); + self::assertSame($certContents, $e->getPrevious()?->getPrevious()?->getMessage()); self::assertSame([ 'name' => '', @@ -355,6 +369,8 @@ public function validate_certificate_purpose_is_not_supported(): void self::fail('Exception was expected.'); } catch (UnsupportedPurpose $e) { + self::assertTranslationEquals('The certificate does not support the purpose: S/MIME signing.', $e); + self::assertEquals(['required_purpose' => new TranslatableArgument('S/MIME signing', domain: 'messages')], $e->getParameters()); } } @@ -397,6 +413,8 @@ public function validate_certificate_host_is_not_supported(string $cert, string self::fail('Exception was expected.'); } catch (UnsupportedDomain $e) { + self::assertTranslationEquals(sprintf('The certificate should support host pattern "%s". But only the following patterns are supported: %s.', $hostPattern, $supported), $e); + self::assertSame(['required_pattern' => $hostPattern, 'supported' => $supported], $e->getParameters()); } } diff --git a/tests/KeyValidatorTest.php b/tests/KeyValidatorTest.php index a9fd921..91c0630 100644 --- a/tests/KeyValidatorTest.php +++ b/tests/KeyValidatorTest.php @@ -19,7 +19,7 @@ use PHPUnit\Framework\TestCase; use Rollerworks\Component\X509Validator\KeyValidator; use Rollerworks\Component\X509Validator\Violation\KeyBitsTooLow; -use Rollerworks\Component\X509Validator\Violation\PublicKeyMismatch; +use Rollerworks\Component\X509Validator\Violation\PrivateKeyMismatch; use Rollerworks\Component\X509Validator\Violation\UnprocessableKey; use Rollerworks\Component\X509Validator\Violation\UnprocessablePEM; @@ -28,38 +28,46 @@ */ final class KeyValidatorTest extends TestCase { + use TranslatorAssertionTrait; + #[Test] public function it_fails_with_invalid_private_key(): void { $validator = new KeyValidator(); - $this->expectException(UnprocessableKey::class); - $this->expectExceptionMessage('Unable to read private key-data'); + try { + $validator->validate( + new HiddenString('-----BEGIN RSA PRIVATE KEY-----NOPE NOPE-----END RSA PRIVATE KEY-----'), + <<<'CERT' + -----BEGIN CERTIFICATE----- + MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS + b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH + DAlSb3R0ZXJkYW0xCzAJBgNVBAYTAk5MMB4XDTE0MDcyNzEzMDIzM1oXDTE4MDcy + NjEzMDIzM1owWzEhMB8GA1UEAwwYYm9wLmRldi5yb2xsZXJzY2FwZXMubmV0MRUw + EwYDVQQKDAxSb2xsZXJzY2FwZXMxEjAQBgNVBAcMCVJvdHRlcmRhbTELMAkGA1UE + BhMCTkwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFN7758InBPIIE + Q/VoYrj/poR1bGEcupAB+Q68R2C5ac5EGQMwaODCphP1RetLGHJE+4hss9GzJb56 + LfLSKy500Zk6R50zUXNCJwvkMvODHTMDy0xORg7tMbe3kLnHH/lbhmeWmXt5qDxa + S2jx5A2pKGmoLS8smYFlPRZ0yiK8Ugy5kDWCEFA31TIsGKcofOWcr+vfJ7HltXav + h1VFZ2nzJC8xKaoFQO4uake225CZQ+W4yhIxu5beY/FXlh2PIZqd1rQhQLuV5gK4 + zGkjNkN6DVJ+7xwnYJ7yeXKlovwMOEJQG1LHnr16gFRRcFeVUHPZkW47QGOYh60n + rG8/8/kLAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAKLWz2F2bJyhTlHxAORbdugm + esBbPxlhkCitdXp7uAkQh+0HeJ+jFb+CA0blmGyY3j15t54WV9ySMV8tQRSk5sXl + VVaJ4AF0uIvT5gbOvL8Vr2ZNiWp2S0Nqx28JVP/KNCAI3PBIWnDcQOON3gHQQi9O + qmL+vAuODEQ2UvgCd2GgFPqsu79Y1PRbqRIwqNiFasHt9pQNlpzRM6AjtUMldShG + rpz1WIZIIZuH+TC/iqD7UlSoLxJbe79a6dbBNw7bnWlo+HDl8YfmY6Ks3O6MCbYn + qVBRc3K9ywcUYPJNVuUazdXuY6FSiGB1iOLxRHppQapmWK5GdtQFXW3GlkXFYf4= + -----END CERTIFICATE----- + CERT + ); - $validator->validate( - new HiddenString('-----BEGIN RSA PRIVATE KEY-----NOPE NOPE-----END RSA PRIVATE KEY-----'), - <<<'CERT' - -----BEGIN CERTIFICATE----- - MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS - b2xsZXJzY2FwZXMgQ0F2MzEVMBMGA1UECgwMUm9sbGVyc2NhcGVzMRIwEAYDVQQH - DAlSb3R0ZXJkYW0xCzAJBgNVBAYTAk5MMB4XDTE0MDcyNzEzMDIzM1oXDTE4MDcy - NjEzMDIzM1owWzEhMB8GA1UEAwwYYm9wLmRldi5yb2xsZXJzY2FwZXMubmV0MRUw - EwYDVQQKDAxSb2xsZXJzY2FwZXMxEjAQBgNVBAcMCVJvdHRlcmRhbTELMAkGA1UE - BhMCTkwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFN7758InBPIIE - Q/VoYrj/poR1bGEcupAB+Q68R2C5ac5EGQMwaODCphP1RetLGHJE+4hss9GzJb56 - LfLSKy500Zk6R50zUXNCJwvkMvODHTMDy0xORg7tMbe3kLnHH/lbhmeWmXt5qDxa - S2jx5A2pKGmoLS8smYFlPRZ0yiK8Ugy5kDWCEFA31TIsGKcofOWcr+vfJ7HltXav - h1VFZ2nzJC8xKaoFQO4uake225CZQ+W4yhIxu5beY/FXlh2PIZqd1rQhQLuV5gK4 - zGkjNkN6DVJ+7xwnYJ7yeXKlovwMOEJQG1LHnr16gFRRcFeVUHPZkW47QGOYh60n - rG8/8/kLAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAKLWz2F2bJyhTlHxAORbdugm - esBbPxlhkCitdXp7uAkQh+0HeJ+jFb+CA0blmGyY3j15t54WV9ySMV8tQRSk5sXl - VVaJ4AF0uIvT5gbOvL8Vr2ZNiWp2S0Nqx28JVP/KNCAI3PBIWnDcQOON3gHQQi9O - qmL+vAuODEQ2UvgCd2GgFPqsu79Y1PRbqRIwqNiFasHt9pQNlpzRM6AjtUMldShG - rpz1WIZIIZuH+TC/iqD7UlSoLxJbe79a6dbBNw7bnWlo+HDl8YfmY6Ks3O6MCbYn - qVBRc3K9ywcUYPJNVuUazdXuY6FSiGB1iOLxRHppQapmWK5GdtQFXW3GlkXFYf4= - -----END CERTIFICATE----- - CERT - ); + self::fail('Exception was expected.'); + } catch (UnprocessableKey $e) { + self::assertEquals('Unable to read private key-data, invalid key provided?', $e->getMessage()); + self::assertNotEmpty($e->getPrevious()?->getMessage()); + + self::assertTranslationEquals('Unable to process private key. Only PEM encoded X.509 files are supported.', $e); + } } #[Test] @@ -67,46 +75,50 @@ public function it_fails_with_invalid_cert(): void { $validator = new KeyValidator(); - $this->expectException(UnprocessablePEM::class); + try { + $validator->validate( + new HiddenString( + <<<'PRIV_KEY' + -----BEGIN RSA PRIVATE KEY----- + MIIEogIBAAKCAQEAxTe++fCJwTyCBEP1aGK4/6aEdWxhHLqQAfkOvEdguWnORBkD + MGjgwqYT9UXrSxhyRPuIbLPRsyW+ei3y0isudNGZOkedM1FzQicL5DLzgx0zA8tM + TkYO7TG3t5C5xx/5W4Znlpl7eag8Wkto8eQNqShpqC0vLJmBZT0WdMoivFIMuZA1 + ghBQN9UyLBinKHzlnK/r3yex5bV2r4dVRWdp8yQvMSmqBUDuLmpHttuQmUPluMoS + MbuW3mPxV5YdjyGanda0IUC7leYCuMxpIzZDeg1Sfu8cJ2Ce8nlypaL8DDhCUBtS + x569eoBUUXBXlVBz2ZFuO0BjmIetJ6xvP/P5CwIDAQABAoIBAEZcy0A1N5C/28tV + y7rAbiyX5m5WipdLYJGzoDRAaxv7yeG14tNkt7v6sOgzV+1k/W/rJhNSXKDD+J9y + wU2Gpn57QWXvowBqMOsLL0zteL/wrQDPiZvrluu9b0SI2B9ZIwgqfc7XV5xiD5ZP + jVOv/8e4aWndJRWOdwH9t4NXkukI5Joc/l0JvLVlteBwJO22JvWp3skBiNBCwP/e + +tx9570QJederODEkf0wPpD4PSMM86GpP5x0+NGfO+fn0AD2adSmOSRnzO769AzH + l3R5Oh2tMFgnyxmLYpa/DL1XAgR6vIPkgJOVkcbg19yps+f35Mi1n9e63QDEB8lI + fkRFtAECgYEA6Wxvd9miW5ts02K34oxm/UWp6trZKthhWQ0J2JDn7dvO6KnyIzpw + cfEv6wRHxtSot/VkV1Qf6YwPKvl8KkYVDXbs9AZ4nzEXp6GSkf2SEGx2h2Gofiwq + DkWRnaI/1kM4ukzW16PiumTd8KQis6V7/2y9Kw1t9u2DyYUv6KfIUAsCgYEA2Era + 4jQ4VQMJBBY8pQN+gMpH+avytvGGHXl/tm6My7LevEZOq00LAhlsa/fwUxI1dXhH + yFXtQIILZw79a1bRWsbfFrkWiC9g0JgNDt/pzds2EsTltVS5OWRMaVcrL3glP8+U + ObW4qzTJiI6m6LKV7hnmaL1fR/NUjWk+fvc/mwECgYAMs3fFP7RT47siLWbwDs+z + zEyYmNvkNu3lGI6GmCvmh2VUx5qDTDS+Hm+LDCqTqRKdH98b2Vn7LUHOBtE4w6N1 + nhj6ljeOAe/VkTcWdoOyHRS9/RRb+S84o5RuzVtH31SA3pl6FlLJ7Z8d7vBscf6z + QUlxxENNglL/bh3TPP3rTQKBgC8LwSZ4s1QSb/CaoaBG7Uo4NYWiGA4g5MoedmAJ + Fcjs5DPRmyT5gg531zR43qZDDKu7eOmjfxKL9sz43rhtTuZO4ZGAutzuaUGWASke + HS3wo4dbmpdhkVRhc5lqI3OUz41cqmIPG9bpiXiRhs6QoboDmjFoF4R/8gE8RiK5 + xvUBAoGACrghAg+GlJZ/Aogx7wK6b1k8rfcpgIoHxOPiqIgyMgevTT6D6w8D0CqI + cEVTZ/fm+EaNuMZvxqSG5f19/obLus+VNXvnMYi3qwFAZ5NhKBen12YhIcaZpOh1 + ZSjeYozDCyRmv76q3sqcLrwxnULIcaK0l255ZczzwiUl39Bqe1o= + -----END RSA PRIVATE KEY----- + PRIV_KEY + ), + <<<'CERT' + -----BEGIN CERTIFICATE----- + MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS + -----END CERTIFICATE----- + CERT + ); - $validator->validate( - new HiddenString( - $privateKey = <<<'PRIV_KEY' - -----BEGIN RSA PRIVATE KEY----- - MIIEogIBAAKCAQEAxTe++fCJwTyCBEP1aGK4/6aEdWxhHLqQAfkOvEdguWnORBkD - MGjgwqYT9UXrSxhyRPuIbLPRsyW+ei3y0isudNGZOkedM1FzQicL5DLzgx0zA8tM - TkYO7TG3t5C5xx/5W4Znlpl7eag8Wkto8eQNqShpqC0vLJmBZT0WdMoivFIMuZA1 - ghBQN9UyLBinKHzlnK/r3yex5bV2r4dVRWdp8yQvMSmqBUDuLmpHttuQmUPluMoS - MbuW3mPxV5YdjyGanda0IUC7leYCuMxpIzZDeg1Sfu8cJ2Ce8nlypaL8DDhCUBtS - x569eoBUUXBXlVBz2ZFuO0BjmIetJ6xvP/P5CwIDAQABAoIBAEZcy0A1N5C/28tV - y7rAbiyX5m5WipdLYJGzoDRAaxv7yeG14tNkt7v6sOgzV+1k/W/rJhNSXKDD+J9y - wU2Gpn57QWXvowBqMOsLL0zteL/wrQDPiZvrluu9b0SI2B9ZIwgqfc7XV5xiD5ZP - jVOv/8e4aWndJRWOdwH9t4NXkukI5Joc/l0JvLVlteBwJO22JvWp3skBiNBCwP/e - +tx9570QJederODEkf0wPpD4PSMM86GpP5x0+NGfO+fn0AD2adSmOSRnzO769AzH - l3R5Oh2tMFgnyxmLYpa/DL1XAgR6vIPkgJOVkcbg19yps+f35Mi1n9e63QDEB8lI - fkRFtAECgYEA6Wxvd9miW5ts02K34oxm/UWp6trZKthhWQ0J2JDn7dvO6KnyIzpw - cfEv6wRHxtSot/VkV1Qf6YwPKvl8KkYVDXbs9AZ4nzEXp6GSkf2SEGx2h2Gofiwq - DkWRnaI/1kM4ukzW16PiumTd8KQis6V7/2y9Kw1t9u2DyYUv6KfIUAsCgYEA2Era - 4jQ4VQMJBBY8pQN+gMpH+avytvGGHXl/tm6My7LevEZOq00LAhlsa/fwUxI1dXhH - yFXtQIILZw79a1bRWsbfFrkWiC9g0JgNDt/pzds2EsTltVS5OWRMaVcrL3glP8+U - ObW4qzTJiI6m6LKV7hnmaL1fR/NUjWk+fvc/mwECgYAMs3fFP7RT47siLWbwDs+z - zEyYmNvkNu3lGI6GmCvmh2VUx5qDTDS+Hm+LDCqTqRKdH98b2Vn7LUHOBtE4w6N1 - nhj6ljeOAe/VkTcWdoOyHRS9/RRb+S84o5RuzVtH31SA3pl6FlLJ7Z8d7vBscf6z - QUlxxENNglL/bh3TPP3rTQKBgC8LwSZ4s1QSb/CaoaBG7Uo4NYWiGA4g5MoedmAJ - Fcjs5DPRmyT5gg531zR43qZDDKu7eOmjfxKL9sz43rhtTuZO4ZGAutzuaUGWASke - HS3wo4dbmpdhkVRhc5lqI3OUz41cqmIPG9bpiXiRhs6QoboDmjFoF4R/8gE8RiK5 - xvUBAoGACrghAg+GlJZ/Aogx7wK6b1k8rfcpgIoHxOPiqIgyMgevTT6D6w8D0CqI - cEVTZ/fm+EaNuMZvxqSG5f19/obLus+VNXvnMYi3qwFAZ5NhKBen12YhIcaZpOh1 - ZSjeYozDCyRmv76q3sqcLrwxnULIcaK0l255ZczzwiUl39Bqe1o= - -----END RSA PRIVATE KEY----- - PRIV_KEY - ), - <<<'CERT' - -----BEGIN CERTIFICATE----- - MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS - -----END CERTIFICATE----- - CERT - ); + self::fail('Exception was expected.'); + } catch (UnprocessablePEM $e) { + self::assertTranslationEquals('Unable to process certificate. Only PEM encoded X.509 files are supported.', $e); + } } #[Test] @@ -114,83 +126,87 @@ public function it_fails_with_key_mismatch(): void { $validator = new KeyValidator(); - $this->expectException(PublicKeyMismatch::class); + try { + $validator->validate( + new HiddenString( + <<<'PRIV_KEY' + -----BEGIN RSA PRIVATE KEY----- + MIIEogIBAAKCAQEAxTe++fCJwTyCBEP1aGK4/6aEdWxhHLqQAfkOvEdguWnORBkD + MGjgwqYT9UXrSxhyRPuIbLPRsyW+ei3y0isudNGZOkedM1FzQicL5DLzgx0zA8tM + TkYO7TG3t5C5xx/5W4Znlpl7eag8Wkto8eQNqShpqC0vLJmBZT0WdMoivFIMuZA1 + ghBQN9UyLBinKHzlnK/r3yex5bV2r4dVRWdp8yQvMSmqBUDuLmpHttuQmUPluMoS + MbuW3mPxV5YdjyGanda0IUC7leYCuMxpIzZDeg1Sfu8cJ2Ce8nlypaL8DDhCUBtS + x569eoBUUXBXlVBz2ZFuO0BjmIetJ6xvP/P5CwIDAQABAoIBAEZcy0A1N5C/28tV + y7rAbiyX5m5WipdLYJGzoDRAaxv7yeG14tNkt7v6sOgzV+1k/W/rJhNSXKDD+J9y + wU2Gpn57QWXvowBqMOsLL0zteL/wrQDPiZvrluu9b0SI2B9ZIwgqfc7XV5xiD5ZP + jVOv/8e4aWndJRWOdwH9t4NXkukI5Joc/l0JvLVlteBwJO22JvWp3skBiNBCwP/e + +tx9570QJederODEkf0wPpD4PSMM86GpP5x0+NGfO+fn0AD2adSmOSRnzO769AzH + l3R5Oh2tMFgnyxmLYpa/DL1XAgR6vIPkgJOVkcbg19yps+f35Mi1n9e63QDEB8lI + fkRFtAECgYEA6Wxvd9miW5ts02K34oxm/UWp6trZKthhWQ0J2JDn7dvO6KnyIzpw + cfEv6wRHxtSot/VkV1Qf6YwPKvl8KkYVDXbs9AZ4nzEXp6GSkf2SEGx2h2Gofiwq + DkWRnaI/1kM4ukzW16PiumTd8KQis6V7/2y9Kw1t9u2DyYUv6KfIUAsCgYEA2Era + 4jQ4VQMJBBY8pQN+gMpH+avytvGGHXl/tm6My7LevEZOq00LAhlsa/fwUxI1dXhH + yFXtQIILZw79a1bRWsbfFrkWiC9g0JgNDt/pzds2EsTltVS5OWRMaVcrL3glP8+U + ObW4qzTJiI6m6LKV7hnmaL1fR/NUjWk+fvc/mwECgYAMs3fFP7RT47siLWbwDs+z + zEyYmNvkNu3lGI6GmCvmh2VUx5qDTDS+Hm+LDCqTqRKdH98b2Vn7LUHOBtE4w6N1 + nhj6ljeOAe/VkTcWdoOyHRS9/RRb+S84o5RuzVtH31SA3pl6FlLJ7Z8d7vBscf6z + QUlxxENNglL/bh3TPP3rTQKBgC8LwSZ4s1QSb/CaoaBG7Uo4NYWiGA4g5MoedmAJ + Fcjs5DPRmyT5gg531zR43qZDDKu7eOmjfxKL9sz43rhtTuZO4ZGAutzuaUGWASke + HS3wo4dbmpdhkVRhc5lqI3OUz41cqmIPG9bpiXiRhs6QoboDmjFoF4R/8gE8RiK5 + xvUBAoGACrghAg+GlJZ/Aogx7wK6b1k8rfcpgIoHxOPiqIgyMgevTT6D6w8D0CqI + cEVTZ/fm+EaNuMZvxqSG5f19/obLus+VNXvnMYi3qwFAZ5NhKBen12YhIcaZpOh1 + ZSjeYozDCyRmv76q3sqcLrwxnULIcaK0l255ZczzwiUl39Bqe1o= + -----END RSA PRIVATE KEY----- + PRIV_KEY + ), + <<<'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 + -----END CERTIFICATE----- + CERT + ); - $validator->validate( - new HiddenString( - $privateKey = <<<'PRIV_KEY' - -----BEGIN RSA PRIVATE KEY----- - MIIEogIBAAKCAQEAxTe++fCJwTyCBEP1aGK4/6aEdWxhHLqQAfkOvEdguWnORBkD - MGjgwqYT9UXrSxhyRPuIbLPRsyW+ei3y0isudNGZOkedM1FzQicL5DLzgx0zA8tM - TkYO7TG3t5C5xx/5W4Znlpl7eag8Wkto8eQNqShpqC0vLJmBZT0WdMoivFIMuZA1 - ghBQN9UyLBinKHzlnK/r3yex5bV2r4dVRWdp8yQvMSmqBUDuLmpHttuQmUPluMoS - MbuW3mPxV5YdjyGanda0IUC7leYCuMxpIzZDeg1Sfu8cJ2Ce8nlypaL8DDhCUBtS - x569eoBUUXBXlVBz2ZFuO0BjmIetJ6xvP/P5CwIDAQABAoIBAEZcy0A1N5C/28tV - y7rAbiyX5m5WipdLYJGzoDRAaxv7yeG14tNkt7v6sOgzV+1k/W/rJhNSXKDD+J9y - wU2Gpn57QWXvowBqMOsLL0zteL/wrQDPiZvrluu9b0SI2B9ZIwgqfc7XV5xiD5ZP - jVOv/8e4aWndJRWOdwH9t4NXkukI5Joc/l0JvLVlteBwJO22JvWp3skBiNBCwP/e - +tx9570QJederODEkf0wPpD4PSMM86GpP5x0+NGfO+fn0AD2adSmOSRnzO769AzH - l3R5Oh2tMFgnyxmLYpa/DL1XAgR6vIPkgJOVkcbg19yps+f35Mi1n9e63QDEB8lI - fkRFtAECgYEA6Wxvd9miW5ts02K34oxm/UWp6trZKthhWQ0J2JDn7dvO6KnyIzpw - cfEv6wRHxtSot/VkV1Qf6YwPKvl8KkYVDXbs9AZ4nzEXp6GSkf2SEGx2h2Gofiwq - DkWRnaI/1kM4ukzW16PiumTd8KQis6V7/2y9Kw1t9u2DyYUv6KfIUAsCgYEA2Era - 4jQ4VQMJBBY8pQN+gMpH+avytvGGHXl/tm6My7LevEZOq00LAhlsa/fwUxI1dXhH - yFXtQIILZw79a1bRWsbfFrkWiC9g0JgNDt/pzds2EsTltVS5OWRMaVcrL3glP8+U - ObW4qzTJiI6m6LKV7hnmaL1fR/NUjWk+fvc/mwECgYAMs3fFP7RT47siLWbwDs+z - zEyYmNvkNu3lGI6GmCvmh2VUx5qDTDS+Hm+LDCqTqRKdH98b2Vn7LUHOBtE4w6N1 - nhj6ljeOAe/VkTcWdoOyHRS9/RRb+S84o5RuzVtH31SA3pl6FlLJ7Z8d7vBscf6z - QUlxxENNglL/bh3TPP3rTQKBgC8LwSZ4s1QSb/CaoaBG7Uo4NYWiGA4g5MoedmAJ - Fcjs5DPRmyT5gg531zR43qZDDKu7eOmjfxKL9sz43rhtTuZO4ZGAutzuaUGWASke - HS3wo4dbmpdhkVRhc5lqI3OUz41cqmIPG9bpiXiRhs6QoboDmjFoF4R/8gE8RiK5 - xvUBAoGACrghAg+GlJZ/Aogx7wK6b1k8rfcpgIoHxOPiqIgyMgevTT6D6w8D0CqI - cEVTZ/fm+EaNuMZvxqSG5f19/obLus+VNXvnMYi3qwFAZ5NhKBen12YhIcaZpOh1 - ZSjeYozDCyRmv76q3sqcLrwxnULIcaK0l255ZczzwiUl39Bqe1o= - -----END RSA PRIVATE KEY----- - PRIV_KEY - ), - <<<'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 - -----END CERTIFICATE----- - CERT - ); + self::fail('Exception was expected.'); + } catch (PrivateKeyMismatch $e) { + self::assertTranslationEquals('The certificate does not match with the provided private-key.', $e); + } } #[Test] @@ -200,7 +216,7 @@ public function it_accepts_valid_data(): void $validator = new KeyValidator(); $validator->validate( new HiddenString( - $privateKey = <<<'PRIV_KEY' + <<<'PRIV_KEY' -----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAxTe++fCJwTyCBEP1aGK4/6aEdWxhHLqQAfkOvEdguWnORBkD MGjgwqYT9UXrSxhyRPuIbLPRsyW+ei3y0isudNGZOkedM1FzQicL5DLzgx0zA8tM @@ -261,7 +277,7 @@ public function it_accepts_hidden_string_data(): void $validator = new KeyValidator(); $validator->validate( new HiddenString( - $privateKey = <<<'PRIV_KEY' + <<<'PRIV_KEY' -----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAxTe++fCJwTyCBEP1aGK4/6aEdWxhHLqQAfkOvEdguWnORBkD MGjgwqYT9UXrSxhyRPuIbLPRsyW+ei3y0isudNGZOkedM1FzQicL5DLzgx0zA8tM @@ -320,43 +336,49 @@ public function it_fails_with_low_bit_count(): void { $validator = new KeyValidator(); - $this->expectException(KeyBitsTooLow::class); + try { + $validator->validate( + <<<'PRIV_KEY' + -----BEGIN RSA PRIVATE KEY----- + MIICXQIBAAKBgQDGdG43UwH+zGYaPX6TxGglJh9/YRZx2H40nZ5Z05z5nkJXDI7k + rrcs/fBLJRgi9AIcdueLLaq1cSp2rwlMVOYOXpMg1MKnXb2fYm0s1/7283ZzoylL + 1872IJLPmm2Hw5wnNldqTHU9YfOlUEpqSHNV6WNsYr7GTjGfCSSec34d4wIDAQAB + AoGAMCZ9u2SjfkvflgxHkti7oA/Q4poO1Q5/CIsZqZfDZXk1hWNhpDCT9xGh5Mma + QpjLjlZ3NXieC6nqcKNlcSTEMFizRXpvfDnG7IANuBdp77eoZHhheTLY5yKxhzfN + ZBokcgAGcOKPNkCZ6ARb2sMvwm92KK8OhwGC38bq0YRu3bECQQDxskH4LqPw7px2 + 5UdNWvnAmBwpmW9GsIjs3W8lH003hdrZ67//qAI+tVgA2SkFM382PQ/mEjQ65B48 + N7Ct3/6ZAkEA0jMOZHWjjC8zwCOLn4FXL51YcclojEFQkThx+CMp7H+3Xhqa6KT4 + CZgYf9Llq9s0wA1bMhCpMZ7JEzTzlHF52wJBAMEn247S/1Ox7bsbGvOYLBaduYwJ + QiO1O4hIouWA8X3Y7IDR5jwTcc/Zrz3mTuEIObcH76fHjpQt8HfhbcJXS6kCQQCG + IyrGFQQ/S0f9DzHkogdfTUvJoTvkdTHS2nBwZxAz6fS8SsIcQFpA1RydRZpnJ0Xs + YRmXQ2aVUb0DUsE2M4wNAkAfJiHdKiDDwUU7YkONkpNLn1eFRyylDsEzdCB2VeSR + wGZWY+ujFtu9MYnSf9N14DdZInHfVen8xBpX+xDeKS9E + -----END RSA PRIVATE KEY----- + PRIV_KEY + , + <<<'CERT' + -----BEGIN CERTIFICATE----- + MIICEzCCAXwCCQCmaz9evnQZlzANBgkqhkiG9w0BAQsFADBOMRQwEgYDVQQDDAtl + eGFtcGxlLmNvbTEQMA4GA1UECgwHRXhhbXBsZTEXMBUGA1UEBwwOV2FzaGhpbmd0 + b24gQUMxCzAJBgNVBAYTAlVTMB4XDTIwMDUwMzEzMTMzNloXDTI0MDUwMjEzMTMz + NlowTjEUMBIGA1UEAwwLZXhhbXBsZS5jb20xEDAOBgNVBAoMB0V4YW1wbGUxFzAV + BgNVBAcMDldhc2hoaW5ndG9uIEFDMQswCQYDVQQGEwJVUzCBnzANBgkqhkiG9w0B + AQEFAAOBjQAwgYkCgYEAxnRuN1MB/sxmGj1+k8RoJSYff2EWcdh+NJ2eWdOc+Z5C + VwyO5K63LP3wSyUYIvQCHHbniy2qtXEqdq8JTFTmDl6TINTCp129n2JtLNf+9vN2 + c6MpS9fO9iCSz5pth8OcJzZXakx1PWHzpVBKakhzVeljbGK+xk4xnwkknnN+HeMC + AwEAATANBgkqhkiG9w0BAQsFAAOBgQCs+IaMmYEK9+/xcGjA0xAVCeLGurd1EFT/ + PinGAxLF+3xURpECwQhESASj5yDVzEz4A3RBLoel3mSFVqUqxJceo6X0gE0TwvtL + xKOFZRRuMCEI7mqHBykhMJIYWBesg3+Uh02u0olK7+CkdSrmSZd8CZtm+imCCaYr + jSHjiAFydw== + -----END CERTIFICATE----- + CERT + ); - $validator->validate( - <<<'PRIV_KEY' - -----BEGIN RSA PRIVATE KEY----- - MIICXQIBAAKBgQDGdG43UwH+zGYaPX6TxGglJh9/YRZx2H40nZ5Z05z5nkJXDI7k - rrcs/fBLJRgi9AIcdueLLaq1cSp2rwlMVOYOXpMg1MKnXb2fYm0s1/7283ZzoylL - 1872IJLPmm2Hw5wnNldqTHU9YfOlUEpqSHNV6WNsYr7GTjGfCSSec34d4wIDAQAB - AoGAMCZ9u2SjfkvflgxHkti7oA/Q4poO1Q5/CIsZqZfDZXk1hWNhpDCT9xGh5Mma - QpjLjlZ3NXieC6nqcKNlcSTEMFizRXpvfDnG7IANuBdp77eoZHhheTLY5yKxhzfN - ZBokcgAGcOKPNkCZ6ARb2sMvwm92KK8OhwGC38bq0YRu3bECQQDxskH4LqPw7px2 - 5UdNWvnAmBwpmW9GsIjs3W8lH003hdrZ67//qAI+tVgA2SkFM382PQ/mEjQ65B48 - N7Ct3/6ZAkEA0jMOZHWjjC8zwCOLn4FXL51YcclojEFQkThx+CMp7H+3Xhqa6KT4 - CZgYf9Llq9s0wA1bMhCpMZ7JEzTzlHF52wJBAMEn247S/1Ox7bsbGvOYLBaduYwJ - QiO1O4hIouWA8X3Y7IDR5jwTcc/Zrz3mTuEIObcH76fHjpQt8HfhbcJXS6kCQQCG - IyrGFQQ/S0f9DzHkogdfTUvJoTvkdTHS2nBwZxAz6fS8SsIcQFpA1RydRZpnJ0Xs - YRmXQ2aVUb0DUsE2M4wNAkAfJiHdKiDDwUU7YkONkpNLn1eFRyylDsEzdCB2VeSR - wGZWY+ujFtu9MYnSf9N14DdZInHfVen8xBpX+xDeKS9E - -----END RSA PRIVATE KEY----- - PRIV_KEY - , - <<<'CERT' - -----BEGIN CERTIFICATE----- - MIICEzCCAXwCCQCmaz9evnQZlzANBgkqhkiG9w0BAQsFADBOMRQwEgYDVQQDDAtl - eGFtcGxlLmNvbTEQMA4GA1UECgwHRXhhbXBsZTEXMBUGA1UEBwwOV2FzaGhpbmd0 - b24gQUMxCzAJBgNVBAYTAlVTMB4XDTIwMDUwMzEzMTMzNloXDTI0MDUwMjEzMTMz - NlowTjEUMBIGA1UEAwwLZXhhbXBsZS5jb20xEDAOBgNVBAoMB0V4YW1wbGUxFzAV - BgNVBAcMDldhc2hoaW5ndG9uIEFDMQswCQYDVQQGEwJVUzCBnzANBgkqhkiG9w0B - AQEFAAOBjQAwgYkCgYEAxnRuN1MB/sxmGj1+k8RoJSYff2EWcdh+NJ2eWdOc+Z5C - VwyO5K63LP3wSyUYIvQCHHbniy2qtXEqdq8JTFTmDl6TINTCp129n2JtLNf+9vN2 - c6MpS9fO9iCSz5pth8OcJzZXakx1PWHzpVBKakhzVeljbGK+xk4xnwkknnN+HeMC - AwEAATANBgkqhkiG9w0BAQsFAAOBgQCs+IaMmYEK9+/xcGjA0xAVCeLGurd1EFT/ - PinGAxLF+3xURpECwQhESASj5yDVzEz4A3RBLoel3mSFVqUqxJceo6X0gE0TwvtL - xKOFZRRuMCEI7mqHBykhMJIYWBesg3+Uh02u0olK7+CkdSrmSZd8CZtm+imCCaYr - jSHjiAFydw== - -----END CERTIFICATE----- - CERT - ); + self::fail('Exception was expected.'); + } catch (KeyBitsTooLow $e) { + self::assertSame(['expected' => 2048, 'provided' => 1024], $e->getParameters()); + + self::assertTranslationEquals('The private-key bits-size 1024 is too low. Expected at least 2048 bits.', $e); + } } } diff --git a/tests/OCSPValidatorTest.php b/tests/OCSPValidatorTest.php index a5ce20d..d39007b 100644 --- a/tests/OCSPValidatorTest.php +++ b/tests/OCSPValidatorTest.php @@ -36,6 +36,7 @@ final class OCSPValidatorTest extends TestCase { use ProphecyTrait; + use TranslatorAssertionTrait; private OCSPValidator $certificateValidator; @@ -68,28 +69,8 @@ public function validate_certificate_is_actually_readable(): void } catch (UnprocessablePEM $e) { self::assertSame(['name' => ''], $e->getParameters()); self::assertSame($certContents, $e->getPrevious()?->getPrevious()?->getMessage()); - } - } - #[Test] - public function validate_certificate_data_is_readable(): void - { - $certContents = <<<'CERT' - -----BEGIN CERTIFICATE----- - MIIDKzCCAhMCCQDZHE66hI+pmjANBgkqhkiG9w0BAQUFADBUMRowGAYDVQQDDBFS - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - -----END CERTIFICATE----- - CERT; - - try { - $this->certificateValidator->validateStatus($certContents); - - self::fail('Exception was expected.'); - } catch (UnprocessablePEM $e) { - self::assertSame($certContents, $e->getPrevious()?->getPrevious()?->getMessage()); - self::assertSame([ - 'name' => '', - ], $e->getParameters()); + self::assertTranslationEquals('Unable to process certificate. Only PEM encoded X.509 files are supported.', $e); } } @@ -220,9 +201,11 @@ public function validate_certificate_is_revoked(): void self::assertEquals([ 'revoked_on' => new \DateTimeImmutable('2023-03-16T19:37:43.000000+0000'), 'reason_code' => 'unspecified', - 'reason' => new TranslatableArgument('unspecified (no specific reason was given).'), + 'reason' => new TranslatableArgument('no specific reason was given'), 'serial' => '7459839413651464540545224973334900563', ], $e->getParameters()); + + self::assertTranslationEquals('The certificate with serial-number "7459839413651464540545224973334900563" was marked as revoked on 3/16/23 with reason: (unspecified) no specific reason was given.', $e); } } diff --git a/tests/TranslatorAssertionTrait.php b/tests/TranslatorAssertionTrait.php new file mode 100644 index 0000000..99bee08 --- /dev/null +++ b/tests/TranslatorAssertionTrait.php @@ -0,0 +1,35 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Rollerworks\Component\X509Validator\Tests; + +use PHPUnit\Framework\Assert; +use Rollerworks\Component\X509Validator\Violation; +use Symfony\Component\Translation\Loader\XliffFileLoader; +use Symfony\Component\Translation\Translator; + +trait TranslatorAssertionTrait +{ + private static function assertTranslationEquals(string $expected, Violation $e): void + { + static $translator; + + if (! isset($translator)) { + $translator = new Translator('en'); + $translator->addLoader('xliff', new XliffFileLoader()); + $translator->addResource('xliff', \dirname(__DIR__) . '/Resources/translations/validators+intl-icu.en.xliff', 'en', 'validators+intl-icu'); + } + + Assert::assertEquals($expected, $e->trans($translator)); + } +}