From 4a05eb08cf6e387ba4f24994b7b7e99da0514a15 Mon Sep 17 00:00:00 2001 From: Florent Morselli Date: Mon, 24 Jun 2024 18:31:57 +0200 Subject: [PATCH] Replace PHP_EOL with "\n" in certificate processing (#574) * Replace PHP_EOL with "\n" in certificate processing The PHP_EOL constant used in certificate processing has been replaced with "\n". This change impacts multiple files including KeyConverter.php, ECKey.php, and X5UFactory.php. The commit ensures consistent use of line breaks across various operating systems. --- composer.json | 24 ++++++------- deptrac.yaml | 34 ++++++++++--------- phpunit.xml.dist | 2 +- rector.php | 6 ++-- src/Deprecated/Core/composer.json | 2 +- .../SignatureAlgorithm/EdDSA/composer.json | 2 +- src/Library/Core/Util/ECKey.php | 13 ++++--- .../KeyConverter/KeyConverter.php | 19 +++++------ src/Library/KeyManagement/X5UFactory.php | 3 +- src/Library/composer.json | 4 +-- .../KeyManagement/JWKSetLoaderTest.php | 5 +-- .../KeyManagement/JWKFactoryTest.php | 18 +++++----- tests/autoload.php | 9 +++++ 13 files changed, 74 insertions(+), 67 deletions(-) create mode 100644 tests/autoload.php diff --git a/composer.json b/composer.json index 76a5f595c..5be74c0ee 100644 --- a/composer.json +++ b/composer.json @@ -53,8 +53,8 @@ "ext-openssl": "*", "ext-sodium": "*", "brick/math": "^0.9|^0.10|^0.11|^0.12", - "paragonie/constant_time_encoding": "^2.6", - "paragonie/sodium_compat": "^1.20", + "paragonie/constant_time_encoding": "^2.6|^3.0", + "paragonie/sodium_compat": "^1.20|^2.0", "psr/cache": "^3.0", "psr/clock": "^1.0", "psr/event-dispatcher": "^1.0", @@ -75,7 +75,7 @@ "ext-gmp": "*", "bjeavons/zxcvbn-php": "^1.3", "ekino/phpstan-banned-code": "^1.0", - "infection/infection": "^0.27", + "infection/infection": "^0.29", "matthiasnoback/symfony-config-test": "^5.0", "nyholm/psr7": "^1.8", "php-http/mock-client": "^1.5", @@ -86,17 +86,17 @@ "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "^10.1", - "qossmic/deptrac-shim": "^1.0", + "phpunit/phpunit": "^10.1|^11.0", + "qossmic/deptrac": "^2.0", "rector/rector": "^1.0", "roave/security-advisories": "dev-latest", - "symfony/browser-kit": "^6.1|^7.0", - "symfony/finder": "^6.1|^7.0", - "symfony/framework-bundle": "^6.1|^7.0", - "symfony/phpunit-bridge": "^6.1|^7.0", - "symfony/serializer": "^6.1|^7.0", - "symfony/var-dumper": "^6.1|^7.0", - "symfony/yaml": "^6.1|^7.0", + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^5.4|^6.0|^7.0", + "symfony/serializer": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0", "symplify/easy-coding-standard": "^12.0" }, "replace": { diff --git a/deptrac.yaml b/deptrac.yaml index f0df02726..705b626df 100644 --- a/deptrac.yaml +++ b/deptrac.yaml @@ -4,38 +4,40 @@ parameters: layers: - name: 'Core' collectors: - - { type: className, regex: '^Jose\\Component\\Core\\' } + - { type: classLike, value: '^Jose\\Component\\Core\\' } - name: 'Checker' collectors: - - { type: className, regex: '^Jose\\Component\\Checker\\' } + - { type: classLike, value: '^Jose\\Component\\Checker\\' } - name: 'Console' collectors: - - { type: className, regex: '^Jose\\Component\\Console\\' } + - { type: classLike, value: '^Jose\\Component\\Console\\' } - name: 'KeyManagement' collectors: - - { type: className, regex: '^Jose\\Component\\KeyManagement\\' } + - { type: classLike, value: '^Jose\\Component\\KeyManagement\\' } - name: 'NestedToken' collectors: - - { type: className, regex: '^Jose\\Component\\NestedToken\\' } + - { type: classLike, value: '^Jose\\Component\\NestedToken\\' } - name: 'Encryption' collectors: - - { type: className, regex: '^Jose\\Component\\Encryption\\' } + - { type: classLike, value: '^Jose\\Component\\Encryption\\' } - name: 'Signature' collectors: - - { type: className, regex: '^Jose\\Component\\Signature\\' } + - { type: classLike, value: '^Jose\\Component\\Signature\\' } - name: 'Bundle' collectors: - - { type: className, regex: '^Jose\\Bundle\\JoseFramework\\' } + - { type: classLike, value: '^Jose\\Bundle\\JoseFramework\\' } - name: 'Vendors' collectors: - - { type: className, regex: '^Symfony\\' } - - { type: className, regex: '^SpomkyLabs\\Pki\\' } - - { type: className, regex: '^ParagonIE\\' } - - { type: className, regex: '^Psr\\EventDispatcher\\' } - - { type: className, regex: '^Psr\\Http\\' } - - { type: className, regex: '^Brick\\Math\\' } - - { type: className, regex: '^AESKW\\' } - - { type: className, regex: '^ZxcvbnPhp\\' } + - { type: classLike, value: '^Symfony\\' } + - { type: classLike, value: '^SpomkyLabs\\Pki\\' } + - { type: classLike, value: '^ParagonIE\\' } + - { type: classLike, value: '^Psr\\EventDispatcher\\' } + - { type: classLike, value: '^Psr\\Http\\' } + - { type: classLike, value: '^Psr\\Cache\\' } + - { type: classLike, value: '^Psr\\Clock\\' } + - { type: classLike, value: '^Brick\\Math\\' } + - { type: classLike, value: '^AESKW\\' } + - { type: classLike, value: '^ZxcvbnPhp\\' } ruleset: Core: - 'Vendors' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 5e5d862e9..02d1a774e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -4,7 +4,7 @@ backupGlobals="false" processIsolation="false" stopOnFailure="false" - bootstrap="vendor/autoload.php" + bootstrap="tests/autoload.php" beStrictAboutTestsThatDoNotTestAnything="false" colors="true" xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" diff --git a/rector.php b/rector.php index 69897c226..9793d157f 100644 --- a/rector.php +++ b/rector.php @@ -5,18 +5,16 @@ use Rector\Config\RectorConfig; use Rector\Doctrine\Set\DoctrineSetList; use Rector\PHPUnit\CodeQuality\Rector\Class_\PreferPHPUnitThisCallRector; -use Rector\PHPUnit\Set\PHPUnitLevelSetList; use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Set\ValueObject\LevelSetList; use Rector\Set\ValueObject\SetList; -use Rector\Symfony\Set\SymfonyLevelSetList; use Rector\Symfony\Set\SymfonySetList; use Rector\ValueObject\PhpVersion; return static function (RectorConfig $config): void { $config->import(SetList::DEAD_CODE); $config->import(LevelSetList::UP_TO_PHP_81); - $config->import(SymfonyLevelSetList::UP_TO_SYMFONY_54); + $config->import(SymfonySetList::SYMFONY_54); $config->import(SymfonySetList::SYMFONY_50_TYPES); $config->import(SymfonySetList::SYMFONY_52_VALIDATOR_ATTRIBUTES); $config->import(SymfonySetList::SYMFONY_CODE_QUALITY); @@ -26,7 +24,7 @@ $config->import(DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES); $config->import(PHPUnitSetList::PHPUNIT_CODE_QUALITY); $config->import(PHPUnitSetList::ANNOTATIONS_TO_ATTRIBUTES); - $config->import(PHPUnitLevelSetList::UP_TO_PHPUNIT_100); + $config->import(PHPUnitSetList::PHPUNIT_100); $config->paths([ __DIR__ . '/ecs.php', __DIR__ . '/rector.php', diff --git a/src/Deprecated/Core/composer.json b/src/Deprecated/Core/composer.json index 783ad95da..2e4732e27 100644 --- a/src/Deprecated/Core/composer.json +++ b/src/Deprecated/Core/composer.json @@ -37,7 +37,7 @@ "ext-json": "*", "ext-mbstring": "*", "brick/math": "^0.9|^0.10|^0.11|^0.12", - "paragonie/constant_time_encoding": "^2.6", + "paragonie/constant_time_encoding": "^2.6|^3.0", "spomky-labs/pki-framework": "^1.2.1", "web-token/jwt-library": "^3.3" } diff --git a/src/Deprecated/SignatureAlgorithm/EdDSA/composer.json b/src/Deprecated/SignatureAlgorithm/EdDSA/composer.json index f572be837..f5bd1abb9 100644 --- a/src/Deprecated/SignatureAlgorithm/EdDSA/composer.json +++ b/src/Deprecated/SignatureAlgorithm/EdDSA/composer.json @@ -35,7 +35,7 @@ "require": { "php": ">=8.1", "ext-sodium": "*", - "paragonie/sodium_compat": "^1.20", + "paragonie/sodium_compat": "^1.20|^2.0", "web-token/jwt-library": "^3.3" } } diff --git a/src/Library/Core/Util/ECKey.php b/src/Library/Core/Util/ECKey.php index 6cef96876..aa4aac88c 100644 --- a/src/Library/Core/Util/ECKey.php +++ b/src/Library/Core/Util/ECKey.php @@ -12,7 +12,6 @@ use function is_array; use function is_string; use const OPENSSL_KEYTYPE_EC; -use const PHP_EOL; use const STR_PAD_LEFT; /** @@ -39,10 +38,10 @@ public static function convertPublicKeyToPEM(JWK $jwk): string default => throw new InvalidArgumentException('Unsupported curve.'), }; $der .= self::getKey($jwk); - $pem = '-----BEGIN PUBLIC KEY-----' . PHP_EOL; - $pem .= chunk_split(base64_encode($der), 64, PHP_EOL); + $pem = '-----BEGIN PUBLIC KEY-----' . "\n"; + $pem .= chunk_split(base64_encode($der), 64, "\n"); - return $pem . ('-----END PUBLIC KEY-----' . PHP_EOL); + return $pem . ('-----END PUBLIC KEY-----' . "\n"); } public static function convertPrivateKeyToPEM(JWK $jwk): string @@ -55,10 +54,10 @@ public static function convertPrivateKeyToPEM(JWK $jwk): string default => throw new InvalidArgumentException('Unsupported curve.'), }; $der .= self::getKey($jwk); - $pem = '-----BEGIN EC PRIVATE KEY-----' . PHP_EOL; - $pem .= chunk_split(base64_encode($der), 64, PHP_EOL); + $pem = '-----BEGIN EC PRIVATE KEY-----' . "\n"; + $pem .= chunk_split(base64_encode($der), 64, "\n"); - return $pem . ('-----END EC PRIVATE KEY-----' . PHP_EOL); + return $pem . ('-----END EC PRIVATE KEY-----' . "\n"); } /** diff --git a/src/Library/KeyManagement/KeyConverter/KeyConverter.php b/src/Library/KeyManagement/KeyConverter/KeyConverter.php index d7a0238f5..4c8d938b7 100644 --- a/src/Library/KeyManagement/KeyConverter/KeyConverter.php +++ b/src/Library/KeyManagement/KeyConverter/KeyConverter.php @@ -28,7 +28,6 @@ use const OPENSSL_KEYTYPE_EC; use const OPENSSL_KEYTYPE_RSA; use const OPENSSL_RAW_DATA; -use const PHP_EOL; use const PREG_PATTERN_ORDER; /** @@ -145,10 +144,10 @@ public static function loadFromX5C(array $x5c): array throw new InvalidArgumentException('The certificate chain is empty'); } foreach ($x5c as $id => $cert) { - $x5c[$id] = '-----BEGIN CERTIFICATE-----' . PHP_EOL . chunk_split( + $x5c[$id] = '-----BEGIN CERTIFICATE-----' . "\n" . chunk_split( (string) $cert, 64, - PHP_EOL + "\n" ) . '-----END CERTIFICATE-----'; $x509 = openssl_x509_read($x5c[$id]); if ($x509 === false) { @@ -372,9 +371,9 @@ private static function sanitizePEM(string &$pem): void $ciphertext = preg_replace('#-.*-|\r|\n| #', '', $pem); - $pem = $matches[0][0] . PHP_EOL; - $pem .= chunk_split($ciphertext ?? '', 64, PHP_EOL); - $pem .= $matches[0][1] . PHP_EOL; + $pem = $matches[0][0] . "\n"; + $pem .= chunk_split($ciphertext ?? '', 64, "\n"); + $pem .= $matches[0][1] . "\n"; } /** @@ -405,16 +404,16 @@ private static function decodePem(string $pem, array $matches, ?string $password throw new InvalidArgumentException('Unable to load the key'); } - $pem = $result[0][0] . PHP_EOL; + $pem = $result[0][0] . "\n"; $pem .= chunk_split(base64_encode($decoded), 64); - return $pem . ($result[0][1] . PHP_EOL); + return $pem . ($result[0][1] . "\n"); } private static function convertDerToPem(string $der_data): string { - $pem = chunk_split(base64_encode($der_data), 64, PHP_EOL); + $pem = chunk_split(base64_encode($der_data), 64, "\n"); - return '-----BEGIN CERTIFICATE-----' . PHP_EOL . $pem . '-----END CERTIFICATE-----' . PHP_EOL; + return '-----BEGIN CERTIFICATE-----' . "\n" . $pem . '-----END CERTIFICATE-----' . "\n"; } } diff --git a/src/Library/KeyManagement/X5UFactory.php b/src/Library/KeyManagement/X5UFactory.php index 1eaf9bf52..f08c2d8ed 100644 --- a/src/Library/KeyManagement/X5UFactory.php +++ b/src/Library/KeyManagement/X5UFactory.php @@ -11,7 +11,6 @@ use RuntimeException; use function is_array; use function is_string; -use const PHP_EOL; class X5UFactory extends UrlKeySetFactory { @@ -29,7 +28,7 @@ public function loadFromUrl(string $url, array $header = []): JWKSet $keys = []; foreach ($data as $kid => $cert) { if (mb_strpos((string) $cert, '-----BEGIN CERTIFICATE-----') === false) { - $cert = '-----BEGIN CERTIFICATE-----' . PHP_EOL . $cert . PHP_EOL . '-----END CERTIFICATE-----'; + $cert = '-----BEGIN CERTIFICATE-----' . "\n" . $cert . "\n" . '-----END CERTIFICATE-----'; } $jwk = KeyConverter::loadKeyFromCertificate($cert); if (is_string($kid)) { diff --git a/src/Library/composer.json b/src/Library/composer.json index 271a683ff..fee12b478 100644 --- a/src/Library/composer.json +++ b/src/Library/composer.json @@ -42,8 +42,8 @@ "ext-json": "*", "ext-mbstring": "*", "brick/math": "^0.9|^0.10|^0.11|^0.12", - "paragonie/constant_time_encoding": "^2.6", - "paragonie/sodium_compat": "^1.20", + "paragonie/constant_time_encoding": "^2.6|^3.0", + "paragonie/sodium_compat": "^1.20|^2.0", "psr/cache": "^3.0", "psr/clock": "^1.0", "psr/http-factory": "^1.0", diff --git a/tests/Bundle/JoseFramework/Functional/KeyManagement/JWKSetLoaderTest.php b/tests/Bundle/JoseFramework/Functional/KeyManagement/JWKSetLoaderTest.php index 235ba33f3..2bb625767 100644 --- a/tests/Bundle/JoseFramework/Functional/KeyManagement/JWKSetLoaderTest.php +++ b/tests/Bundle/JoseFramework/Functional/KeyManagement/JWKSetLoaderTest.php @@ -9,6 +9,7 @@ use PHPUnit\Framework\Attributes\Test; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** @@ -33,7 +34,7 @@ public static function aJWKSetCanBeSharedInTheConfiguration(): void static::ensureKernelShutdown(); $client = static::createClient(); - $client->request('GET', '/keys/1.jwkset'); + $client->request(Request::METHOD_GET, '/keys/1.jwkset'); /** @var Response $response */ $response = $client->getResponse(); @@ -62,7 +63,7 @@ public static function aJWKSetCanBeSharedFromAnotherBundle(): void static::ensureKernelShutdown(); $client = static::createClient(); - $client->request('GET', '/keys/2.jwkset'); + $client->request(Request::METHOD_GET, '/keys/2.jwkset'); /** @var Response $response */ $response = $client->getResponse(); diff --git a/tests/Component/KeyManagement/JWKFactoryTest.php b/tests/Component/KeyManagement/JWKFactoryTest.php index c777b5034..aadcdf2a1 100644 --- a/tests/Component/KeyManagement/JWKFactoryTest.php +++ b/tests/Component/KeyManagement/JWKFactoryTest.php @@ -245,7 +245,7 @@ public static function dataKeys(): iterable { yield [ 'filename' => __DIR__ . '/Keys/ED/public-ed448.pem', - 'values' => [ + 'expectedValues' => [ 'kty' => 'OKP', 'crv' => 'Ed448', 'x' => 'wwHKDV7s4fBhmFSTzYorlaToGXNcsa7SakZdekT_sexD5ENj5lWP6_KX9_u--w_QSm80rNOodj0A', @@ -253,7 +253,7 @@ public static function dataKeys(): iterable ]; yield [ 'filename' => __DIR__ . '/Keys/ED/public-ed25519.pem', - 'values' => [ + 'expectedValues' => [ 'kty' => 'OKP', 'crv' => 'Ed25519', 'x' => 'wrI33AEj15KHHYplueUE5cnJKtbM8oVHFf6wGnw2oOE', @@ -261,7 +261,7 @@ public static function dataKeys(): iterable ]; yield [ 'filename' => __DIR__ . '/Keys/ED/public-X448.pem', - 'values' => [ + 'expectedValues' => [ 'kty' => 'OKP', 'crv' => 'X448', 'x' => 'UoPD73NQACC8A-otDUVun4IrMsk775ShMRf4ThDrq4xY2eAI-pOIVujrvBXXd9g8gUNwBT0fmnc', @@ -269,7 +269,7 @@ public static function dataKeys(): iterable ]; yield [ 'filename' => __DIR__ . '/Keys/ED/public-X25519.pem', - 'values' => [ + 'expectedValues' => [ 'kty' => 'OKP', 'crv' => 'X25519', 'x' => '3OJLiffmOCQGtil23QGyn0nk9EBKoZx6P-6o-EnsBB4', @@ -277,7 +277,7 @@ public static function dataKeys(): iterable ]; yield [ 'filename' => __DIR__ . '/Keys/ED/private-ed448.pem', - 'values' => [ + 'expectedValues' => [ 'kty' => 'OKP', 'crv' => 'Ed448', 'd' => '0GXSbNLOh7NQBlwoF8y2WJmjeP5Puif4_JL4ihFUzRLrb_3r4cH8l_HWJA-2ffY62LEB_ozsehG5', @@ -285,7 +285,7 @@ public static function dataKeys(): iterable ]; yield [ 'filename' => __DIR__ . '/Keys/ED/private-X448.pem', - 'values' => [ + 'expectedValues' => [ 'kty' => 'OKP', 'crv' => 'X448', 'd' => 'OHZK0Fp9MAAmk0yZekiAkB8qxpCVAF4dT2x_xmFNDdCTnyDvixaiZ0NSRpAdR59tA6OJmOFfbck', @@ -293,7 +293,7 @@ public static function dataKeys(): iterable ]; yield [ 'filename' => __DIR__ . '/Keys/ED/private-ed25519.pem', - 'values' => [ + 'expectedValues' => [ 'kty' => 'OKP', 'crv' => 'Ed25519', 'd' => 'Pr9AxZivB-zSq95wLrZfYa7DQ3TUPqZTkP_0w33r3rc', @@ -302,7 +302,7 @@ public static function dataKeys(): iterable ]; yield [ 'filename' => __DIR__ . '/Keys/ED/private-secp384r1-with-public.pem', - 'values' => [ + 'expectedValues' => [ 'kty' => 'EC', 'crv' => 'P-384', 'd' => '31taDOPQnlNl2aBC_EaGTqVGjGN_qg6iuLwP6cVTmhKMQ5PTL67wS6mmyKi8GdVP', @@ -312,7 +312,7 @@ public static function dataKeys(): iterable ]; yield [ 'filename' => __DIR__ . '/Keys/ED/private-X25519.pem', - 'values' => [ + 'expectedValues' => [ 'kty' => 'OKP', 'crv' => 'X25519', 'd' => 'mG-fgDwkr58hwIeqCQKZbR8HKeY4yg_AzvU6zyNaVUE', diff --git a/tests/autoload.php b/tests/autoload.php new file mode 100644 index 000000000..552064b8f --- /dev/null +++ b/tests/autoload.php @@ -0,0 +1,9 @@ +