Skip to content

Commit

Permalink
Provide Sodium base64 polyfill for libsodium < 1.0.14
Browse files Browse the repository at this point in the history
  • Loading branch information
Slamdunk committed Feb 12, 2021
1 parent 944b16c commit 3a72bba
Show file tree
Hide file tree
Showing 16 changed files with 272 additions and 23 deletions.
5 changes: 5 additions & 0 deletions infection.json.dist
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
"Lcobucci\\JWT\\Signer\\Ecdsa\\MultibyteStringConverter::preparePositiveInteger"
]
},
"LogicalNot": {
"ignoreSourceCodeByRegex": [
"if \\(!function_exists\\('sodium_\\w+'\\)\\) \\{"
]
},
"MBString": {
"ignore": [
"Lcobucci\\JWT\\Signer\\Ecdsa\\MultibyteStringConverter"
Expand Down
5 changes: 2 additions & 3 deletions src/Encoding/CannotDecodeContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use JsonException;
use Lcobucci\JWT\Exception;
use RuntimeException;
use SodiumException;

final class CannotDecodeContent extends RuntimeException implements Exception
{
Expand All @@ -15,8 +14,8 @@ public static function jsonIssues(JsonException $previous): self
return new self('Error while decoding from JSON', 0, $previous);
}

public static function invalidBase64String(SodiumException $sodiumException): self
public static function invalidBase64String(): self
{
return new self('Error while decoding from Base64Url, invalid base64 characters detected', 0, $sodiumException);
return new self('Error while decoding from Base64Url, invalid base64 characters detected');
}
}
19 changes: 9 additions & 10 deletions src/Encoding/JoseEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@
use JsonException;
use Lcobucci\JWT\Decoder;
use Lcobucci\JWT\Encoder;
use SodiumException;
use Lcobucci\JWT\SodiumBase64Polyfill;

use function json_decode;
use function json_encode;
use function sodium_base642bin;
use function sodium_bin2base64;

use const JSON_THROW_ON_ERROR;
use const JSON_UNESCAPED_SLASHES;
use const JSON_UNESCAPED_UNICODE;
use const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING;

/**
* A utilitarian class that encodes and decodes data according with JOSE specifications
Expand Down Expand Up @@ -47,15 +44,17 @@ public function jsonDecode(string $json)

public function base64UrlEncode(string $data): string
{
return sodium_bin2base64($data, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING);
return SodiumBase64Polyfill::bin2base64(
$data,
SodiumBase64Polyfill::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
);
}

public function base64UrlDecode(string $data): string
{
try {
return sodium_base642bin($data, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING, '');
} catch (SodiumException $sodiumException) {
throw CannotDecodeContent::invalidBase64String($sodiumException);
}
return SodiumBase64Polyfill::base642bin(
$data,
SodiumBase64Polyfill::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
);
}
}
15 changes: 5 additions & 10 deletions src/Signer/Key/InMemory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,13 @@

namespace Lcobucci\JWT\Signer\Key;

use Lcobucci\JWT\Encoding\CannotDecodeContent;
use Lcobucci\JWT\Signer\Key;
use SodiumException;
use Lcobucci\JWT\SodiumBase64Polyfill;
use SplFileObject;
use Throwable;

use function assert;
use function is_string;
use function sodium_base642bin;

use const SODIUM_BASE64_VARIANT_ORIGINAL;

final class InMemory implements Key
{
Expand All @@ -38,11 +34,10 @@ public static function plainText(string $contents, string $passphrase = ''): sel

public static function base64Encoded(string $contents, string $passphrase = ''): self
{
try {
$decoded = sodium_base642bin($contents, SODIUM_BASE64_VARIANT_ORIGINAL, '');
} catch (SodiumException $sodiumException) {
throw CannotDecodeContent::invalidBase64String($sodiumException);
}
$decoded = SodiumBase64Polyfill::base642bin(
$contents,
SodiumBase64Polyfill::SODIUM_BASE64_VARIANT_ORIGINAL
);

return new self($decoded, $passphrase);
}
Expand Down
88 changes: 88 additions & 0 deletions src/SodiumBase64Polyfill.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php
declare(strict_types=1);

namespace Lcobucci\JWT;

use Lcobucci\JWT\Encoding\CannotDecodeContent;
use SodiumException;

use function base64_decode;
use function base64_encode;
use function function_exists;
use function is_string;
use function rtrim;
use function sodium_base642bin;
use function sodium_bin2base64;
use function strtr;

/** @internal */
final class SodiumBase64Polyfill
{
public const SODIUM_BASE64_VARIANT_ORIGINAL = 1;
public const SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
public const SODIUM_BASE64_VARIANT_URLSAFE = 5;
public const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING = 7;

public static function bin2base64(string $decoded, int $variant): string
{
if (! function_exists('sodium_bin2base64')) {
return self::bin2base64Fallback($decoded, $variant); // @codeCoverageIgnore
}

return sodium_bin2base64($decoded, $variant);
}

public static function bin2base64Fallback(string $decoded, int $variant): string
{
$encoded = base64_encode($decoded);

if (
$variant === self::SODIUM_BASE64_VARIANT_URLSAFE
|| $variant === self::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
) {
$encoded = strtr($encoded, '+/', '-_');
}

if (
$variant === self::SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING
|| $variant === self::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
) {
$encoded = rtrim($encoded, '=');
}

return $encoded;
}

/** @throws CannotDecodeContent */
public static function base642bin(string $encoded, int $variant): string
{
if (! function_exists('sodium_base642bin')) {
return self::bin2base64Fallback($encoded, $variant); // @codeCoverageIgnore
}

try {
return sodium_base642bin($encoded, $variant, '');
} catch (SodiumException $sodiumException) {
throw CannotDecodeContent::invalidBase64String();
}
}

/** @throws CannotDecodeContent */
public static function base642binFallback(string $encoded, int $variant): string
{
if (
$variant === self::SODIUM_BASE64_VARIANT_URLSAFE
|| $variant === self::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
) {
$encoded = strtr($encoded, '-_', '+/');
}

$decoded = base64_decode($encoded, true);

if (! is_string($decoded)) {
throw CannotDecodeContent::invalidBase64String();
}

return $decoded;
}
}
1 change: 1 addition & 0 deletions test/functional/ES512TokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
* @covers \Lcobucci\JWT\Signer\Ecdsa\Sha512
* @covers \Lcobucci\JWT\Signer\InvalidKeyProvided
* @covers \Lcobucci\JWT\Signer\OpenSSL
* @covers \Lcobucci\JWT\SodiumBase64Polyfill
* @covers \Lcobucci\JWT\Validation\Validator
* @covers \Lcobucci\JWT\Validation\RequiredConstraintsViolated
* @covers \Lcobucci\JWT\Validation\Constraint\SignedWith
Expand Down
1 change: 1 addition & 0 deletions test/functional/EcdsaTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* @covers \Lcobucci\JWT\Signer\Ecdsa\Sha512
* @covers \Lcobucci\JWT\Signer\InvalidKeyProvided
* @covers \Lcobucci\JWT\Signer\OpenSSL
* @covers \Lcobucci\JWT\SodiumBase64Polyfill
* @covers \Lcobucci\JWT\Validation\Validator
* @covers \Lcobucci\JWT\Validation\Constraint\SignedWith
* @covers \Lcobucci\JWT\Validation\Validator
Expand Down
1 change: 1 addition & 0 deletions test/functional/EddsaTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* @covers \Lcobucci\JWT\Signer\Eddsa
* @covers \Lcobucci\JWT\Signer\InvalidKeyProvided
* @covers \Lcobucci\JWT\Signer\OpenSSL
* @covers \Lcobucci\JWT\SodiumBase64Polyfill
* @covers \Lcobucci\JWT\Validation\Validator
* @covers \Lcobucci\JWT\Validation\Constraint\SignedWith
* @covers \Lcobucci\JWT\Validation\Validator
Expand Down
1 change: 1 addition & 0 deletions test/functional/HmacTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
* @covers \Lcobucci\JWT\Signer\Hmac
* @covers \Lcobucci\JWT\Signer\Hmac\Sha256
* @covers \Lcobucci\JWT\Signer\Hmac\Sha512
* @covers \Lcobucci\JWT\SodiumBase64Polyfill
* @covers \Lcobucci\JWT\Validation\Validator
* @covers \Lcobucci\JWT\Validation\RequiredConstraintsViolated
* @covers \Lcobucci\JWT\Validation\Constraint\SignedWith
Expand Down
1 change: 1 addition & 0 deletions test/functional/MaliciousTamperingPreventionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public function createConfiguration(): void
* @covers \Lcobucci\JWT\Signer\Hmac
* @covers \Lcobucci\JWT\Signer\Hmac\Sha256
* @covers \Lcobucci\JWT\Signer\Hmac\Sha512
* @covers \Lcobucci\JWT\SodiumBase64Polyfill
* @covers \Lcobucci\JWT\Validation\Constraint\SignedWith
* @covers \Lcobucci\JWT\Validation\Validator
*/
Expand Down
1 change: 1 addition & 0 deletions test/functional/RsaTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
* @covers \Lcobucci\JWT\Signer\Rsa
* @covers \Lcobucci\JWT\Signer\Rsa\Sha256
* @covers \Lcobucci\JWT\Signer\Rsa\Sha512
* @covers \Lcobucci\JWT\SodiumBase64Polyfill
* @covers \Lcobucci\JWT\Validation\Validator
* @covers \Lcobucci\JWT\Validation\RequiredConstraintsViolated
* @covers \Lcobucci\JWT\Validation\Constraint\SignedWith
Expand Down
1 change: 1 addition & 0 deletions test/functional/UnsignedTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* @covers \Lcobucci\JWT\Token\Signature
* @covers \Lcobucci\JWT\Signer\None
* @covers \Lcobucci\JWT\Signer\Key\InMemory
* @covers \Lcobucci\JWT\SodiumBase64Polyfill
* @covers \Lcobucci\JWT\Validation\RequiredConstraintsViolated
* @covers \Lcobucci\JWT\Validation\Validator
* @covers \Lcobucci\JWT\Validation\Constraint\IssuedBy
Expand Down
10 changes: 10 additions & 0 deletions test/unit/Encoding/JoseEncoderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ public function jsonDecodeMustRaiseExceptionWhenAnErrorHasOccurred(): void
* @test
*
* @covers ::base64UrlEncode
*
* @uses \Lcobucci\JWT\SodiumBase64Polyfill::bin2base64()
*/
public function base64UrlEncodeMustReturnAUrlSafeBase64(): void
{
Expand All @@ -119,6 +121,8 @@ public function base64UrlEncodeMustReturnAUrlSafeBase64(): void
* @test
*
* @covers ::base64UrlEncode
*
* @uses \Lcobucci\JWT\SodiumBase64Polyfill::bin2base64()
*/
public function base64UrlEncodeMustEncodeBilboMessageProperly(): void
{
Expand All @@ -139,6 +143,8 @@ public function base64UrlEncodeMustEncodeBilboMessageProperly(): void
* @test
*
* @covers ::base64UrlDecode
*
* @uses \Lcobucci\JWT\SodiumBase64Polyfill::base642bin()
*/
public function base64UrlDecodeMustRaiseExceptionWhenInvalidBase64CharsAreUsed(): void
{
Expand All @@ -155,6 +161,8 @@ public function base64UrlDecodeMustRaiseExceptionWhenInvalidBase64CharsAreUsed()
* @test
*
* @covers ::base64UrlDecode
*
* @uses \Lcobucci\JWT\SodiumBase64Polyfill::base642bin()
*/
public function base64UrlDecodeMustReturnTheRightData(): void
{
Expand All @@ -170,6 +178,8 @@ public function base64UrlDecodeMustReturnTheRightData(): void
* @test
*
* @covers ::base64UrlDecode
*
* @uses \Lcobucci\JWT\SodiumBase64Polyfill::base642bin()
*/
public function base64UrlDecodeMustDecodeBilboMessageProperly(): void
{
Expand Down
3 changes: 3 additions & 0 deletions test/unit/Signer/EddsaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ public function verifyShouldRaiseAnExceptionWhenKeyIsNotParseable(): void
*
* @uses \Lcobucci\JWT\Encoding\JoseEncoder
* @uses \Lcobucci\JWT\Signer\Key\InMemory
* @uses \Lcobucci\JWT\SodiumBase64Polyfill::base642bin()
* @uses \Lcobucci\JWT\SodiumBase64Polyfill::bin2base64()
*/
public function signatureOfRfcExample(): void
{
Expand Down Expand Up @@ -138,6 +140,7 @@ public function signatureOfRfcExample(): void
*
* @uses \Lcobucci\JWT\Encoding\JoseEncoder
* @uses \Lcobucci\JWT\Signer\Key\InMemory
* @uses \Lcobucci\JWT\SodiumBase64Polyfill::base642bin()
*/
public function verificationOfRfcExample(): void
{
Expand Down
4 changes: 4 additions & 0 deletions test/unit/Signer/Key/InMemoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public function configureRootDir(): void
*
* @covers ::base64Encoded
* @covers \Lcobucci\JWT\Encoding\CannotDecodeContent
*
* @uses \Lcobucci\JWT\SodiumBase64Polyfill::base642bin()
*/
public function exceptionShouldBeRaisedWhenInvalidBase64CharsAreUsed(): void
{
Expand All @@ -42,6 +44,8 @@ public function exceptionShouldBeRaisedWhenInvalidBase64CharsAreUsed(): void
* @covers ::base64Encoded
* @covers ::__construct
* @covers ::contents
*
* @uses \Lcobucci\JWT\SodiumBase64Polyfill::base642bin()
*/
public function base64EncodedShouldDecodeKeyContents(): void
{
Expand Down
Loading

0 comments on commit 3a72bba

Please sign in to comment.