Skip to content

Commit c0aecbd

Browse files
authored
Merge pull request #551 from web-token/temp-1ef6ba
Merge up 3.4.x to 4.0.x
2 parents b2be12f + c66f1b7 commit c0aecbd

File tree

8 files changed

+245
-31
lines changed

8 files changed

+245
-31
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"brick/math": "^0.12",
5454
"psr/clock": "^1.0",
5555
"psr/event-dispatcher": "^1.0",
56-
"spomky-labs/pki-framework": "^1.1",
56+
"spomky-labs/pki-framework": "^1.2.1",
5757
"symfony/config": "^7.0",
5858
"symfony/console": "^7.0",
5959
"symfony/dependency-injection": "^7.0",

phpstan-baseline.neon

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,41 @@ parameters:
18401840
count: 1
18411841
path: src/Library/KeyManagement/KeyConverter/ECKey.php
18421842

1843+
-
1844+
message: "#^Access to an undefined property Jose\\\\Component\\\\KeyManagement\\\\UrlKeySetFactory\\:\\:\\$requestFactory\\.$#"
1845+
count: 1
1846+
path: src/Library/KeyManagement/UrlKeySetFactory.php
1847+
1848+
-
1849+
message: "#^Call to an undefined method Jose\\\\Component\\\\KeyManagement\\\\UrlKeySetFactory\\:\\:sendPsrRequest\\(\\)\\.$#"
1850+
count: 1
1851+
path: src/Library/KeyManagement/UrlKeySetFactory.php
1852+
1853+
-
1854+
message: "#^Call to function assert\\(\\) with true will always evaluate to true\\.$#"
1855+
count: 1
1856+
path: src/Library/KeyManagement/UrlKeySetFactory.php
1857+
1858+
-
1859+
message: "#^Class Psr\\\\Http\\\\Client\\\\ClientInterface not found\\.$#"
1860+
count: 3
1861+
path: src/Library/KeyManagement/UrlKeySetFactory.php
1862+
1863+
-
1864+
message: "#^Instanceof between Symfony\\\\Contracts\\\\HttpClient\\\\HttpClientInterface and Symfony\\\\Contracts\\\\HttpClient\\\\HttpClientInterface will always evaluate to true\\.$#"
1865+
count: 3
1866+
path: src/Library/KeyManagement/UrlKeySetFactory.php
1867+
1868+
-
1869+
message: "#^Method Jose\\\\Component\\\\KeyManagement\\\\UrlKeySetFactory\\:\\:getContent\\(\\) should return string but returns mixed\\.$#"
1870+
count: 1
1871+
path: src/Library/KeyManagement/UrlKeySetFactory.php
1872+
1873+
-
1874+
message: "#^Result of && is always false\\.$#"
1875+
count: 1
1876+
path: src/Library/KeyManagement/UrlKeySetFactory.php
1877+
18431878
-
18441879
message: "#^Parameter \\#2 \\$recipient of method Jose\\\\Component\\\\NestedToken\\\\NestedTokenLoader\\:\\:checkContentTypeHeader\\(\\) expects int, int\\|null given\\.$#"
18451880
count: 1

src/Bundle/DependencyInjection/Source/KeyManagement/JKUSource.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ public function getNodeDefinition(NodeDefinition $node): void
3535
{
3636
$node->children()
3737
->arrayNode('jku_factory')
38-
->canBeEnabled()
39-
->children()
40-
->scalarNode('client')
41-
->info('HTTP Client used to retrieve key sets.')
42-
->isRequired()
43-
->end()
44-
->end()
38+
->canBeEnabled()
39+
->children()
40+
->scalarNode('client')
41+
->info('HTTP Client used to retrieve key sets.')
42+
->isRequired()
4543
->end()
46-
->end();
44+
->end()
45+
->end()
46+
->end();
4747
}
4848

4949
#[Override]

src/Library/KeyManagement/KeyConverter/KeyConverter.php

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44

55
namespace Jose\Component\KeyManagement\KeyConverter;
66

7+
use Brick\Math\BigInteger;
78
use InvalidArgumentException;
89
use Jose\Component\Core\Util\Base64UrlSafe;
910
use OpenSSLCertificate;
1011
use ParagonIE\Sodium\Core\Ed25519;
1112
use RuntimeException;
1213
use SpomkyLabs\Pki\CryptoEncoding\PEM;
14+
use SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\AlgorithmIdentifier;
1315
use SpomkyLabs\Pki\CryptoTypes\Asymmetric\PrivateKey;
1416
use SpomkyLabs\Pki\CryptoTypes\Asymmetric\PublicKey;
17+
use SpomkyLabs\Pki\CryptoTypes\Asymmetric\RSA\RSASSAPSSPrivateKey;
1518
use Throwable;
1619
use function array_key_exists;
1720
use function assert;
@@ -260,31 +263,79 @@ private static function tryToLoadECKey(string $input): array
260263
private static function tryToLoadOtherKeyTypes(string $input): array
261264
{
262265
$pem = PEM::fromString($input);
266+
return match ($pem->type()) {
267+
PEM::TYPE_PUBLIC_KEY => self::loadPublicKey($pem),
268+
PEM::TYPE_PRIVATE_KEY => self::loadPrivateKey($pem),
269+
default => throw new InvalidArgumentException('Unsupported key type'),
270+
};
271+
}
272+
273+
/**
274+
* @return array<string, mixed>
275+
*/
276+
private static function loadPrivateKey(PEM $pem): array
277+
{
263278
try {
264279
$key = PrivateKey::fromPEM($pem);
265-
$curve = self::getCurve($key->algorithmIdentifier()->oid());
266-
$values = [
267-
'kty' => 'OKP',
268-
'crv' => $curve,
269-
'd' => Base64UrlSafe::encodeUnpadded($key->privateKeyData()),
270-
];
271-
return self::populatePoints($key, $values);
272-
} catch (Throwable) {
273-
// no break
280+
switch ($key->algorithmIdentifier()->oid()) {
281+
case AlgorithmIdentifier::OID_RSASSA_PSS_ENCRYPTION:
282+
assert($key instanceof RSASSAPSSPrivateKey);
283+
return [
284+
'kty' => 'RSA',
285+
'n' => self::convertDecimalToBas64Url($key->modulus()),
286+
'e' => self::convertDecimalToBas64Url($key->publicExponent()),
287+
'd' => self::convertDecimalToBas64Url($key->privateExponent()),
288+
'dp' => self::convertDecimalToBas64Url($key->exponent1()),
289+
'dq' => self::convertDecimalToBas64Url($key->exponent2()),
290+
'p' => self::convertDecimalToBas64Url($key->prime1()),
291+
'q' => self::convertDecimalToBas64Url($key->prime2()),
292+
'qi' => self::convertDecimalToBas64Url($key->coefficient()),
293+
];
294+
case AlgorithmIdentifier::OID_ED25519:
295+
case AlgorithmIdentifier::OID_ED448:
296+
case AlgorithmIdentifier::OID_X25519:
297+
case AlgorithmIdentifier::OID_X448:
298+
$curve = self::getCurve($key->algorithmIdentifier()->oid());
299+
$values = [
300+
'kty' => 'OKP',
301+
'crv' => $curve,
302+
'd' => Base64UrlSafe::encodeUnpadded($key->privateKeyData()),
303+
];
304+
return self::populatePoints($key, $values);
305+
default:
306+
throw new InvalidArgumentException('Unsupported key type');
307+
}
308+
} catch (Throwable $e) {
309+
throw new InvalidArgumentException('Unable to load the key.', 0, $e);
274310
}
275-
try {
276-
$key = PublicKey::fromPEM($pem);
277-
$curve = self::getCurve($key->algorithmIdentifier()->oid());
278-
self::checkType($curve);
279-
return [
280-
'kty' => 'OKP',
281-
'crv' => $curve,
282-
'x' => Base64UrlSafe::encodeUnpadded((string) $key->subjectPublicKey()),
283-
];
284-
} catch (Throwable) {
285-
// no break
311+
}
312+
313+
/**
314+
* @return array<string, mixed>
315+
*/
316+
private static function loadPublicKey(PEM $pem): array
317+
{
318+
$key = PublicKey::fromPEM($pem);
319+
switch ($key->algorithmIdentifier()->oid()) {
320+
case AlgorithmIdentifier::OID_ED25519:
321+
case AlgorithmIdentifier::OID_ED448:
322+
case AlgorithmIdentifier::OID_X25519:
323+
case AlgorithmIdentifier::OID_X448:
324+
$curve = self::getCurve($key->algorithmIdentifier()->oid());
325+
self::checkType($curve);
326+
return [
327+
'kty' => 'OKP',
328+
'crv' => $curve,
329+
'x' => Base64UrlSafe::encodeUnpadded((string) $key->subjectPublicKey()),
330+
];
331+
default:
332+
throw new InvalidArgumentException('Unsupported key type');
286333
}
287-
throw new InvalidArgumentException('Unsupported key type');
334+
}
335+
336+
private static function convertDecimalToBas64Url(string $decimal): string
337+
{
338+
return Base64UrlSafe::encodeUnpadded(BigInteger::fromBase($decimal, 10)->toBytes());
288339
}
289340

290341
/**

src/Library/KeyManagement/UrlKeySetFactory.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,79 @@
44

55
namespace Jose\Component\KeyManagement;
66

7+
use Psr\Cache\CacheItemPoolInterface;
8+
use Psr\Http\Client\ClientInterface;
79
use RuntimeException;
10+
use Symfony\Component\Cache\Adapter\NullAdapter;
811
use Symfony\Contracts\HttpClient\HttpClientInterface;
12+
use function assert;
913

1014
/**
1115
* @see \Jose\Tests\Component\KeyManagement\UrlKeySetFactoryTest
1216
*/
1317
abstract class UrlKeySetFactory
1418
{
19+
private CacheItemPoolInterface $cacheItemPool;
20+
21+
private int $expiresAfter = 3600;
22+
1523
public function __construct(
1624
private readonly HttpClientInterface $client,
1725
) {
26+
if ($this->client instanceof ClientInterface) {
27+
trigger_deprecation(
28+
'web-token/jwt-library',
29+
'3.3',
30+
'Using "%s" with an instance of "%s" is deprecated, use "%s" instead.',
31+
self::class,
32+
ClientInterface::class,
33+
HttpClientInterface::class
34+
);
35+
}
36+
if (! $this->client instanceof HttpClientInterface && $this->requestFactory === null) {
37+
throw new RuntimeException(sprintf(
38+
'The request factory must be provided when using an instance of "%s" as client.',
39+
ClientInterface::class
40+
));
41+
}
42+
$this->cacheItemPool = new NullAdapter();
43+
}
44+
45+
public function enabledCache(CacheItemPoolInterface $cacheItemPool, int $expiresAfter = 3600): void
46+
{
47+
$this->cacheItemPool = $cacheItemPool;
48+
$this->expiresAfter = $expiresAfter;
1849
}
1950

2051
/**
2152
* @param array<string, string|string[]> $header
2253
*/
2354
protected function getContent(string $url, array $header = []): string
2455
{
56+
$cacheKey = hash('xxh128', $url);
57+
$item = $this->cacheItemPool->getItem($cacheKey);
58+
if ($item->isHit()) {
59+
return $item->get();
60+
}
61+
62+
$content = $this->client instanceof HttpClientInterface ? $this->sendSymfonyRequest(
63+
$url,
64+
$header
65+
) : $this->sendPsrRequest($url, $header);
66+
$item = $this->cacheItemPool->getItem($cacheKey);
67+
$item->expiresAfter($this->expiresAfter);
68+
$item->set($content);
69+
$this->cacheItemPool->save($item);
70+
71+
return $content;
72+
}
73+
74+
/**
75+
* @param array<string, string|string[]> $header
76+
*/
77+
private function sendSymfonyRequest(string $url, array $header = []): string
78+
{
79+
assert($this->client instanceof HttpClientInterface);
2580
$response = $this->client->request('GET', $url, [
2681
'headers' => $header,
2782
]);

src/Library/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"ext-mbstring": "*",
4444
"brick/math": "^0.12",
4545
"psr/clock": "^1.0",
46-
"spomky-labs/pki-framework": "^1.1"
46+
"spomky-labs/pki-framework": "^1.2.1"
4747
},
4848
"conflict": {
4949
"spomky-labs/jose": "*"
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
-----BEGIN PRIVATE KEY-----
2+
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
51+
fExebCpblM+ctC+gzK6cJMraZGrXbQ==
52+
-----END PRIVATE KEY-----

tests/Component/KeyManagement/Keys/RSAKeysTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,4 +313,25 @@ public function loadPrivateRSAKeyFromMinimalValues(): void
313313
], $public_key->toArray());
314314
static::assertTrue($public_key->isPublic());
315315
}
316+
317+
#[Test]
318+
public function loadsRSASSAPSSKey(): void
319+
{
320+
$key = JWKFactory::createFromKeyFile(__DIR__ . '/RSA/rsassa-pss.pem');
321+
322+
static::assertSame(
323+
[
324+
'kty' => 'RSA',
325+
'n' => 'AL1gIpgcH5QmcNWbRa3AG6DuKIOQYtcUn-UjmB0GaKudvsLWBDId_GiBMo7CoCTIk30WOt2_YRB8BmNGlJB0jJS-fztLx86gP7m5SfFhJJUcAG10Vj2xpkNQZ9aHUyyeNKZpzMBXmlt6k8d-eF_0qJ6v_CpCzkCK3-SFsw22ntCTluuqyiT2UJs0YXK9cpI_4Np8LJPP2Hqb_ByvG1bEit3-k3UWiiK0bwUFe1Gg49GHIfuSCoOAAYNmoZ8rNHQ0SLmo6htwuqKMa7KdEODeEGB2k8gV1tTjag8_ZbdJ0wfhS8YPs_IBwbuicQJlzpNHHW1DRY5XgsJJym9o5Pm5PrD0Q_cjhjOZkEhQs5Y8_XWBE8onlhKt4h9ce5JdfO3qP1H-PG2GnYdIZEXhwQyjqT4_V1agrPD9DHBFW72aWrYfpU7pTry5FsRLaLQJjNDfEYLumYqOVspWgLrr0Er-B1_03VS93kJnq0Y5xglU_p4wRUBKXUn_ntF9Q6Cy2XnaSvIFF3l20IwPPG9wdtjR8kTd21z1IBMVYI0-WLWK3hNXz5C0perOtH51_6-hNP7bG_IrGbILd3EkkZ7Yd3fxX4T0-ZKAoEgQ_4P1A5aJl-2wzEN0r95S62WUcZEXDwXlfkCsWXo3LSdOW8Aht-2xQoGOl5Cx0bd84kfxYGdzBuyh',
326+
'e' => 'AQAB',
327+
'd' => 'A8YQxmnIDiXCdEU89cMztxN2h_b2e0KlqYqkfzk87c-NyQ2RUEDaoj1R2ThYZIdBMM94DT9r2HOKP-FHYwYJikoYrbaFv6YKmGGQefCFlWQ_6hkfgf5NDyoWOaHhIXexGlBWfyONF5h-mE2lPy9C9W-RwDNW2hXSXpgfSxffUWN226Z1KFhRX024yTvXIWzdBumNd1q_faOnr1gkx11mXC8J9_M4KIx31Q3TXmXs_ZnFDqGYl0nTmI9bi45ljru_J8D4PPippW_UJ787bP8L1z-W_rhDBiNr04GKng-I6_nRuVuKf86dvPwV5wD0RVPNVVuEnTCnUhu86UGvOhPhONt2-EPbzJaBb433VC6eO05DJK7JaxrR7vpGn4v4U_xTBUJMTES1-2woPoCjovftMQacNgzoWeuwtFwDdZOkW3rhO5ZEM8msucO3K4AJFRW0MyzGWhUIXqadN_tXKhgKrhgwrQ-M1w4-agBMb_paqIzaePX45YcsT2cd1q_xwr2UM1-8VpfeTouRmiYJINOHiWOsu997H-JTuEpJtpCID6lHDHRoHxpKSEnV4mGSsE74AgdnSvRamDFt8JF2dMdkIOlPrcxXsR8_M0BcQts8vDJ-IQ3RaEbia6vFMSFtTgRK0uV9UuMRp18vQneJXs3GfeDmA7Ej46JCh5m6v0JBNyE',
328+
'dp' => 'AM0IEiWYWSzSz_YsTGKaubsb0vJlwnnN01Kk8coFqQ-5IBUxGVzBVkdVl6HHDKnP1Is0ImA7kLE9BWgHpMSsI4ohocdwJYqYiK3EKx_LjUweSVKm_01almeSUgok0XxFJGrFEFDO9Fvtt8DRElim6TWM8tViH-HXHGtR90IpvEBUlmdoAR-FNMDzB8h5w3OcZOVnYs3CSAB4wCPo3QO7HzfRgAjUt7t16Kd1bDL4qvRKa-ZePg1mQ697yDidAUheJebAuITxfIcnaoIUGD8QGMB1ugwixzEIYWSrSnOSaPwNESHwZPDAUSrqp0axohhqDc0rMdj9kbWWWFL8i4MKSmE',
329+
'dq' => 'AM6bvykUO7YnqHyyXw8G1uO74Vm3bjE7LDON3nLD4-FXBJg2IoVqwghiEsK6s8f3QuY0j1PwXS-PlJuGyUSaBrpn2WSbHA2EwkTihbVW33dW7H0dxaovhHvgCx8HnqmVAaagkHl4M1ZJSiKBrFAR8aSy-0vnnpOHOX3tJVM6pL5BrYUa6INY2uhbXZTXxr4EwBHmpiReYQ4zGrE2kptpI8ikSbkQrfBDv4ARqWILp0a1xFea6KeqvjQ3wTx13OhvNPkLrNNcpy4O32ZiuxkDhIlPrzTwUtaQKiB15qFdoe5a-caPc_TcOTWmkqxE6o7yBiwylIJccqMb_j8xnEuyCnE',
330+
'p' => 'AOCxqqGImEgJgbiHa8bxGICnLq3Aeg1XGhJxW3WBYyhcMLmwUdbu3TeW_wwF_IcWOjbzf4-GtBIbRXtVis9zfPdQpCW2pgVZ77Vl4M0qCJPJz7MVhgzeGoh1KeTSFSba7Da7ZGAgWcWi0HfmZbOv-WjYipIZWQPBFP6u49dsHhO_Icrk7AYWtN07AENnRzIKtENqRp7xItTuDIl4GOqw1_hU9u0XNn7JeMRcPbauqiPT23ZoSCwyPnkKm0ZN74iL2suSTktVW1RFfjIUTQiWt6X-fJ0BgzSb7xqakS65aX9ysAE9SaBAqlIn_fNz3glQziAcNvu5q2htCAuHEdlgufE',
331+
'q' => 'ANfCvLub-wh4ULifAdqFCAjKL-vNiAyJdZ6KFwitioPge889am3kM7A-T45sislBx_MCcQmSm59GyZmRcrOGHCgVt4vwnagQN9fY6k9omUYSCaKiv3yjLhBxAbzwx3Z2pS7E6roa7zEFykaYJGTQprh5K1hrxFeH_kqafln6vNjtQ2E40WdvMli_rr4fOIAidBjxfYjAAb-OmeTpM1IX6L1GwXNZlG9FmD-K8s1xNT9kL55Kk9Vgtr6-lEffTncStYCLC0JBugk4IcwlOZPFwUXmAEnAIGac6hGMh5tXkvQ-SDuo3JbqcQsCSi4aC49ZuA9Gk9wGbtStVwsVKj7nLbE',
332+
'qi' => 'AI7uWbGZxN8e6eQIkTm5VjOS5zic6C1zu1cxfZupmsStI_UYfI0UVSYJ6dOCxMvAqtS2Gqm7P2zyCT-xzkU-XcTxlbMshRKtzg0G8BpfFYcCKjEIqCq8MXpK6osp45SKctKcpFC3H-xl5flbasyx5AW5UQriYErUvP-yitVRuIqv2tKVN8Dl5gMmnuQ32vYZsaOagQqy459T42Y42Vw1N_DYMVe8gdDXpwpItp6IhjmHwmZJcOYBFPKPOKEw3LE7AkvaAfzpznSCY_0v6oD9Fvz6tsFxynRtzhPVFSzDAada1kNjop9h91Kd2nxMXmwqW5TPnLQvoMyunCTK2mRq120',
333+
],
334+
$key->all()
335+
);
336+
}
316337
}

0 commit comments

Comments
 (0)