Skip to content

Commit

Permalink
Merge pull request #855 from Slamdunk/openssl_key_requirements
Browse files Browse the repository at this point in the history
Require minimum key size for OpenSSL keys
  • Loading branch information
lcobucci authored Aug 5, 2022
2 parents 6099cc7 + 82ad9ce commit 1d61d63
Show file tree
Hide file tree
Showing 52 changed files with 1,211 additions and 100 deletions.
45 changes: 28 additions & 17 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,18 @@ $configuration = Configuration::forSymmetricSigner(
Currently supported symmetric algorithms:

| Name | Description | Class | Key length req. |
| --------- | ------------------ | ---------------------------------------- | --------------- |
| `HS256` | HMAC using SHA-256 | `\Lcobucci\JWT\Signer\Hmac\Sha256` | 32 bytes |
| `HS384` | HMAC using SHA-384 | `\Lcobucci\JWT\Signer\Hmac\Sha384` | 48 bytes |
| `HS512` | HMAC using SHA-512 | `\Lcobucci\JWT\Signer\Hmac\Sha512` | 64 bytes |
| --------- | ------------------ | ---------------------------------------- |-----------------|
| `HS256` | HMAC using SHA-256 | `\Lcobucci\JWT\Signer\Hmac\Sha256` | 256 bits |
| `HS384` | HMAC using SHA-384 | `\Lcobucci\JWT\Signer\Hmac\Sha384` | 384 bits |
| `HS512` | HMAC using SHA-512 | `\Lcobucci\JWT\Signer\Hmac\Sha512` | 512 bits |

Deprecated symmetric algorithms in `v4`:

| Name | Description | Class | Key length req. |
| --------- | ------------------ | ---------------------------------------- | --------------- |
| `HS256` | HMAC using SHA-256 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha256` | 1 byte |
| `HS384` | HMAC using SHA-384 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha384` | 1 byte |
| `HS512` | HMAC using SHA-512 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha512` | 1 byte |
| --------- | ------------------ | ---------------------------------------- |-----------------|
| `HS256` | HMAC using SHA-256 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha256` | 1 bit |
| `HS384` | HMAC using SHA-384 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha384` | 1 bit |
| `HS512` | HMAC using SHA-512 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha512` | 1 bit |

#### For asymmetric algorithms

Expand All @@ -109,15 +109,26 @@ $configuration = Configuration::forAsymmetricSigner(

Currently supported asymmetric algorithms:

| Name | Description | Class |
| ------- | ------------------------------- | ----------------------------------- |
| `ES256` | ECDSA using P-256 and SHA-256 | `\Lcobucci\JWT\Signer\Ecdsa\Sha256` |
| `ES384` | ECDSA using P-384 and SHA-384 | `\Lcobucci\JWT\Signer\Ecdsa\Sha384` |
| `ES512` | ECDSA using P-521 and SHA-512 | `\Lcobucci\JWT\Signer\Ecdsa\Sha512` |
| `RS256` | RSASSA-PKCS1-v1_5 using SHA-256 | `\Lcobucci\JWT\Signer\Rsa\Sha256` |
| `RS384` | RSASSA-PKCS1-v1_5 using SHA-384 | `\Lcobucci\JWT\Signer\Rsa\Sha384` |
| `RS512` | RSASSA-PKCS1-v1_5 using SHA-512 | `\Lcobucci\JWT\Signer\Rsa\Sha512` |
| `EdDSA` | EdDSA signature algorithms | `\Lcobucci\JWT\Signer\Eddsa` |
| Name | Description | Class | Key length req. |
| ------- | ------------------------------- | ----------------------------------- |-----------------|
| `ES256` | ECDSA using P-256 and SHA-256 | `\Lcobucci\JWT\Signer\Ecdsa\Sha256` | 224 bits |
| `ES384` | ECDSA using P-384 and SHA-384 | `\Lcobucci\JWT\Signer\Ecdsa\Sha384` | 224 bits |
| `ES512` | ECDSA using P-521 and SHA-512 | `\Lcobucci\JWT\Signer\Ecdsa\Sha512` | 224 bits |
| `RS256` | RSASSA-PKCS1-v1_5 using SHA-256 | `\Lcobucci\JWT\Signer\Rsa\Sha256` | 2048 bits |
| `RS384` | RSASSA-PKCS1-v1_5 using SHA-384 | `\Lcobucci\JWT\Signer\Rsa\Sha384` | 2048 bits |
| `RS512` | RSASSA-PKCS1-v1_5 using SHA-512 | `\Lcobucci\JWT\Signer\Rsa\Sha512` | 2048 bits |
| `EdDSA` | EdDSA signature algorithms | `\Lcobucci\JWT\Signer\Eddsa` | 256 bits |

Deprecated asymmetric algorithms in `v4`:

| Name | Description | Class | Key length req. |
| ------- | ------------------------------- |-------------------------------------------|-----------------|
| `ES256` | ECDSA using P-256 and SHA-256 | `\Lcobucci\JWT\Signer\Ecdsa\UnsafeSha256` | 1 bit |
| `ES384` | ECDSA using P-384 and SHA-384 | `\Lcobucci\JWT\Signer\Ecdsa\UnsafeSha384` | 1 bit |
| `ES512` | ECDSA using P-521 and SHA-512 | `\Lcobucci\JWT\Signer\Ecdsa\UnsafeSha512` | 1 bit |
| `RS256` | RSASSA-PKCS1-v1_5 using SHA-256 | `\Lcobucci\JWT\Signer\Rsa\UnsafeSha256` | 1 bit |
| `RS384` | RSASSA-PKCS1-v1_5 using SHA-384 | `\Lcobucci\JWT\Signer\Rsa\UnsafeSha384` | 1 bit |
| `RS512` | RSASSA-PKCS1-v1_5 using SHA-512 | `\Lcobucci\JWT\Signer\Rsa\UnsafeSha512` | 1 bit |

#### For no algorithm

Expand Down
2 changes: 1 addition & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ parameters:
- '#.*OpenSSLAsymmetricKey.*#'
- '#Call to method .* of deprecated class Lcobucci\\JWT\\Signer\\Key\\LocalFileReference#'
- """
#^Instantiation of deprecated class Lcobucci\\\\JWT\\\\Signer\\\\Hmac\\\\UnsafeSha\\d\\d\\d\\:
#^.+ deprecated class Lcobucci\\\\JWT\\\\Signer\\\\.+:
Deprecated since v4\\.2$#
"""
5 changes: 5 additions & 0 deletions src/Signer/Ecdsa.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ final public function keyType(): int
return OPENSSL_KEYTYPE_EC;
}

final public function minimumBitsLengthForKey(): int
{
return 224;
}

/**
* Returns the length of each point in the signature, so that we can calculate and verify R and S points properly
*
Expand Down
27 changes: 27 additions & 0 deletions src/Signer/Ecdsa/UnsafeSha256.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);

namespace Lcobucci\JWT\Signer\Ecdsa;

use Lcobucci\JWT\Signer\UnsafeEcdsa;

use const OPENSSL_ALGO_SHA256;

/** @deprecated Deprecated since v4.2 */
final class UnsafeSha256 extends UnsafeEcdsa
{
public function algorithmId(): string
{
return 'ES256';
}

public function algorithm(): int
{
return OPENSSL_ALGO_SHA256;
}

public function keyLength(): int
{
return 64;
}
}
27 changes: 27 additions & 0 deletions src/Signer/Ecdsa/UnsafeSha384.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);

namespace Lcobucci\JWT\Signer\Ecdsa;

use Lcobucci\JWT\Signer\UnsafeEcdsa;

use const OPENSSL_ALGO_SHA384;

/** @deprecated Deprecated since v4.2 */
final class UnsafeSha384 extends UnsafeEcdsa
{
public function algorithmId(): string
{
return 'ES384';
}

public function algorithm(): int
{
return OPENSSL_ALGO_SHA384;
}

public function keyLength(): int
{
return 96;
}
}
27 changes: 27 additions & 0 deletions src/Signer/Ecdsa/UnsafeSha512.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);

namespace Lcobucci\JWT\Signer\Ecdsa;

use Lcobucci\JWT\Signer\UnsafeEcdsa;

use const OPENSSL_ALGO_SHA512;

/** @deprecated Deprecated since v4.2 */
final class UnsafeSha512 extends UnsafeEcdsa
{
public function algorithmId(): string
{
return 'ES512';
}

public function algorithm(): int
{
return OPENSSL_ALGO_SHA512;
}

public function keyLength(): int
{
return 132;
}
}
6 changes: 3 additions & 3 deletions src/Signer/Hmac.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ abstract class Hmac implements Signer
{
final public function sign(string $payload, Key $key): string
{
$actualKeyLength = strlen($key->contents());
$expectedKeyLength = $this->minimumBytesLengthForKey();
$actualKeyLength = 8 * strlen($key->contents());
$expectedKeyLength = $this->minimumBitsLengthForKey();
if ($actualKeyLength < $expectedKeyLength) {
throw InvalidKeyProvided::tooShort($expectedKeyLength, $actualKeyLength);
}
Expand All @@ -30,5 +30,5 @@ final public function verify(string $expected, string $payload, Key $key): bool
abstract public function algorithm(): string;

/** @return positive-int */
abstract public function minimumBytesLengthForKey(): int;
abstract public function minimumBitsLengthForKey(): int;
}
4 changes: 2 additions & 2 deletions src/Signer/Hmac/Sha256.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public function algorithm(): string
return 'sha256';
}

public function minimumBytesLengthForKey(): int
public function minimumBitsLengthForKey(): int
{
return 32;
return 256;
}
}
4 changes: 2 additions & 2 deletions src/Signer/Hmac/Sha384.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public function algorithm(): string
return 'sha384';
}

public function minimumBytesLengthForKey(): int
public function minimumBitsLengthForKey(): int
{
return 48;
return 384;
}
}
4 changes: 2 additions & 2 deletions src/Signer/Hmac/Sha512.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public function algorithm(): string
return 'sha512';
}

public function minimumBytesLengthForKey(): int
public function minimumBitsLengthForKey(): int
{
return 64;
return 512;
}
}
2 changes: 1 addition & 1 deletion src/Signer/Hmac/UnsafeSha256.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function algorithm(): string
return 'sha256';
}

public function minimumBytesLengthForKey(): int
public function minimumBitsLengthForKey(): int
{
return 1;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Signer/Hmac/UnsafeSha384.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function algorithm(): string
return 'sha384';
}

public function minimumBytesLengthForKey(): int
public function minimumBitsLengthForKey(): int
{
return 1;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Signer/Hmac/UnsafeSha512.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function algorithm(): string
return 'sha512';
}

public function minimumBytesLengthForKey(): int
public function minimumBitsLengthForKey(): int
{
return 1;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Signer/InvalidKeyProvided.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static function cannotBeEmpty(): self

public static function tooShort(int $expectedLength, int $actualLength): self
{
return new self('Key provided is shorter than ' . $expectedLength . ' bytes,'
. ' only ' . $actualLength . ' bytes provided');
return new self('Key provided is shorter than ' . $expectedLength . ' bits,'
. ' only ' . $actualLength . ' bits provided');
}
}
10 changes: 10 additions & 0 deletions src/Signer/OpenSSL.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use function assert;
use function is_array;
use function is_bool;
use function is_int;
use function is_string;
use function openssl_error_string;
use function openssl_free_key;
Expand Down Expand Up @@ -48,6 +49,9 @@ final protected function createSignature(
}
}

/** @return positive-int */
abstract public function minimumBitsLengthForKey(): int;

/**
* @return resource|OpenSSLAsymmetricKey
*
Expand Down Expand Up @@ -109,6 +113,12 @@ private function validateKey($key): void
if (! array_key_exists('key', $details) || $details['type'] !== $this->keyType()) {
throw InvalidKeyProvided::incompatibleKey();
}

assert(array_key_exists('bits', $details));
assert(is_int($details['bits']));
if ($details['bits'] < $this->minimumBitsLengthForKey()) {
throw InvalidKeyProvided::tooShort($this->minimumBitsLengthForKey(), $details['bits']);
}
}

/** @param resource|OpenSSLAsymmetricKey $key */
Expand Down
5 changes: 5 additions & 0 deletions src/Signer/Rsa.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@ final public function keyType(): int
{
return OPENSSL_KEYTYPE_RSA;
}

final public function minimumBitsLengthForKey(): int
{
return 2048;
}
}
22 changes: 22 additions & 0 deletions src/Signer/Rsa/UnsafeSha256.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);

namespace Lcobucci\JWT\Signer\Rsa;

use Lcobucci\JWT\Signer\UnsafeRsa;

use const OPENSSL_ALGO_SHA256;

/** @deprecated Deprecated since v4.2 */
final class UnsafeSha256 extends UnsafeRsa
{
public function algorithmId(): string
{
return 'RS256';
}

public function algorithm(): int
{
return OPENSSL_ALGO_SHA256;
}
}
22 changes: 22 additions & 0 deletions src/Signer/Rsa/UnsafeSha384.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);

namespace Lcobucci\JWT\Signer\Rsa;

use Lcobucci\JWT\Signer\UnsafeRsa;

use const OPENSSL_ALGO_SHA384;

/** @deprecated Deprecated since v4.2 */
final class UnsafeSha384 extends UnsafeRsa
{
public function algorithmId(): string
{
return 'RS384';
}

public function algorithm(): int
{
return OPENSSL_ALGO_SHA384;
}
}
22 changes: 22 additions & 0 deletions src/Signer/Rsa/UnsafeSha512.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);

namespace Lcobucci\JWT\Signer\Rsa;

use Lcobucci\JWT\Signer\UnsafeRsa;

use const OPENSSL_ALGO_SHA512;

/** @deprecated Deprecated since v4.2 */
final class UnsafeSha512 extends UnsafeRsa
{
public function algorithmId(): string
{
return 'RS512';
}

public function algorithm(): int
{
return OPENSSL_ALGO_SHA512;
}
}
Loading

0 comments on commit 1d61d63

Please sign in to comment.