Skip to content

Commit d67b5d6

Browse files
committed
feat: add key size validation
1 parent a3edb39 commit d67b5d6

File tree

2 files changed

+218
-81
lines changed

2 files changed

+218
-81
lines changed

src/JWT.php

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class JWT
3131
private const ASN1_SEQUENCE = 0x10;
3232
private const ASN1_BIT_STRING = 0x03;
3333

34+
private const RSA_KEY_MIN_LENGTH=2048;
35+
3436
/**
3537
* When checking nbf, iat or expiration times,
3638
* we want to provide some extra leeway time to
@@ -259,11 +261,19 @@ public static function sign(
259261
if (!\is_string($key)) {
260262
throw new InvalidArgumentException('key must be a string when using hmac');
261263
}
264+
self::validateHmacKeyLength($key, $algorithm);
262265
return \hash_hmac($algorithm, $msg, $key, true);
263266
case 'openssl':
264267
$signature = '';
265-
if (!\is_resource($key) && !openssl_pkey_get_private($key)) {
266-
throw new DomainException('OpenSSL unable to validate key');
268+
if (!\is_resource($key)) {
269+
/** @var OpenSSLAsymmetricKey|OpenSSLCertificate|string $key */
270+
$key = $key;
271+
if (!$key = openssl_pkey_get_private($key)) {
272+
throw new DomainException('OpenSSL unable to validate key');
273+
}
274+
if (str_starts_with($alg, 'RS')) {
275+
self::validateRsaKeyLength($key);
276+
}
267277
}
268278
$success = \openssl_sign($msg, $signature, $key, $algorithm); // @phpstan-ignore-line
269279
if (!$success) {
@@ -324,6 +334,13 @@ private static function verify(
324334
list($function, $algorithm) = static::$supported_algs[$alg];
325335
switch ($function) {
326336
case 'openssl':
337+
if (!\is_resource($keyMaterial) && str_starts_with($algorithm, 'RS')) {
338+
/** @var OpenSSLAsymmetricKey|OpenSSLCertificate|string $keyMaterial */
339+
$keyMaterial = $keyMaterial;
340+
if ($key = openssl_pkey_get_private($keyMaterial)) {
341+
self::validateRsaKeyLength($key);
342+
}
343+
}
327344
$success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm); // @phpstan-ignore-line
328345
if ($success === 1) {
329346
return true;
@@ -361,6 +378,7 @@ private static function verify(
361378
if (!\is_string($keyMaterial)) {
362379
throw new InvalidArgumentException('key must be a string when using hmac');
363380
}
381+
self::validateHmacKeyLength($keyMaterial, $algorithm);
364382
$hash = \hash_hmac($algorithm, $msg, $keyMaterial, true);
365383
return self::constantTimeEquals($hash, $signature);
366384
}
@@ -675,4 +693,35 @@ private static function readDER(string $der, int $offset = 0): array
675693

676694
return [$pos, $data];
677695
}
696+
697+
/**
698+
* Validate HMAC key length
699+
*
700+
* @param string $key HMAC key material
701+
* @param string $algorithm The algorithm
702+
* @throws DomainException Provided key is too short
703+
*/
704+
private static function validateHmacKeyLength(string $key, string $algorithm): void
705+
{
706+
$keyLength = \strlen($key) * 8;
707+
$minKeyLength = (int) \str_replace('SHA', '', $algorithm);
708+
if ($keyLength < $minKeyLength) {
709+
throw new DomainException('Provided key is too short');
710+
}
711+
}
712+
713+
/**
714+
* Validate RSA key length
715+
*
716+
* @param OpenSSLAsymmetricKey $key RSA key material
717+
* @throws DomainException Provided key is too short
718+
*/
719+
private static function validateRsaKeyLength(OpenSSLAsymmetricKey $key): void
720+
{
721+
if ($keyDetails = \openssl_pkey_get_details($key)) {
722+
if ($keyDetails['bits'] < self::RSA_KEY_MIN_LENGTH) {
723+
throw new DomainException('Provided key is too short');
724+
}
725+
}
726+
}
678727
}

0 commit comments

Comments
 (0)