Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 78 additions & 3 deletions src/JWT.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
private const ASN1_SEQUENCE = 0x10;
private const ASN1_BIT_STRING = 0x03;

private const RSA_KEY_MIN_LENGTH=2048;

/**
* When checking nbf, iat or expiration times,
* we want to provide some extra leeway time to
Expand Down Expand Up @@ -248,13 +250,26 @@
if (!\is_string($key)) {
throw new InvalidArgumentException('key must be a string when using hmac');
}
self::validateHmacKeyLength($key, $algorithm);
return \hash_hmac($algorithm, $msg, $key, true);
case 'openssl':
$signature = '';
if (!\is_resource($key) && !openssl_pkey_get_private($key)) {
throw new DomainException('OpenSSL unable to validate key');
if (!\is_resource($key)) {
/** @var OpenSSLAsymmetricKey|OpenSSLCertificate|string $key */
$key = $key;
if (!$key = openssl_pkey_get_private($key)) {
throw new DomainException('OpenSSL unable to validate key');
}
if (str_starts_with($alg, 'RS')) {
self::validateRsaKeyLength($key);
}
}
$success = \openssl_sign($msg, $signature, $key, $algorithm); // @phpstan-ignore-line
if (str_starts_with($alg, 'RS')) {
self::validateRsaKeyLength($key);

Check failure on line 268 in src/JWT.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Parameter #1 $key of static method Firebase\JWT\JWT::validateRsaKeyLength() expects OpenSSLAsymmetricKey, OpenSSLAsymmetricKey|resource given.
} elseif (str_starts_with($alg, 'ES')) {
self::validateEcKeyLength($key, $alg);

Check failure on line 270 in src/JWT.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Parameter #1 $key of static method Firebase\JWT\JWT::validateEcKeyLength() expects OpenSSLAsymmetricKey, OpenSSLAsymmetricKey|resource given.
}
$success = \openssl_sign($msg, $signature, $key, $algorithm);

Check failure on line 272 in src/JWT.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Parameter #3 $private_key of function openssl_sign expects array|OpenSSLAsymmetricKey|OpenSSLCertificate|string, OpenSSLAsymmetricKey|resource given.
if (!$success) {
throw new DomainException('OpenSSL unable to sign data');
}
Expand Down Expand Up @@ -313,6 +328,14 @@
list($function, $algorithm) = static::$supported_algs[$alg];
switch ($function) {
case 'openssl':
if (!$key = openssl_pkey_get_public($keyMaterial)) {

Check failure on line 331 in src/JWT.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Parameter #1 $public_key of function openssl_pkey_get_public expects array|OpenSSLAsymmetricKey|OpenSSLCertificate|string, OpenSSLAsymmetricKey|OpenSSLCertificate|resource|string given.
throw new DomainException('OpenSSL unable to validate key');
}
if (str_starts_with($alg, 'RS')) {
self::validateRsaKeyLength($key);
} elseif (str_starts_with($alg, 'ES')) {
self::validateEcKeyLength($key, $alg);
}
$success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm); // @phpstan-ignore-line
if ($success === 1) {
return true;
Expand Down Expand Up @@ -350,6 +373,7 @@
if (!\is_string($keyMaterial)) {
throw new InvalidArgumentException('key must be a string when using hmac');
}
self::validateHmacKeyLength($keyMaterial, $algorithm);
$hash = \hash_hmac($algorithm, $msg, $keyMaterial, true);
return self::constantTimeEquals($hash, $signature);
}
Expand Down Expand Up @@ -664,4 +688,55 @@

return [$pos, $data];
}

/**
* Validate HMAC key length
*
* @param string $key HMAC key material
* @param string $algorithm The algorithm
* @throws DomainException Provided key is too short
*/
private static function validateHmacKeyLength(string $key, string $algorithm): void
{
$keyLength = \strlen($key) * 8;
$minKeyLength = (int) \str_replace('SHA', '', $algorithm);
if ($keyLength < $minKeyLength) {
throw new DomainException('Provided key is too short');
}
}

/**
* Validate RSA key length
*
* @param OpenSSLAsymmetricKey $key RSA key material
* @throws DomainException Provided key is too short
*/
private static function validateRsaKeyLength(OpenSSLAsymmetricKey $key): void
{
if ($keyDetails = \openssl_pkey_get_details($key)) {
if ($keyDetails['bits'] < self::RSA_KEY_MIN_LENGTH) {
throw new DomainException('Provided key is too short');
}
}
}

/**
* Validate EC key length
*
* @param OpenSSLAsymmetricKey $key RSA key material
* @param string $algorithm The algorithm
* @throws DomainException Provided key is too short
*/
private static function validateEcKeyLength(
#[\SensitiveParameter] OpenSSLAsymmetricKey $key,
string $algorithm
): void {
if (!$keyDetails = openssl_pkey_get_details($key)) {
throw new DomainException('Unable to validate key');
}
$minKeyLength = (int) \str_replace('ES', '', $algorithm);
if ($keyDetails['bits'] < $minKeyLength) {
throw new DomainException('Provided key is too short');
}
}
}
Loading
Loading