diff --git a/.idea/php.xml b/.idea/php.xml index 6e91387..cee48e7 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -123,7 +123,7 @@ - + diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml index 12d6855..4609cff 100644 --- a/.idea/sqldialects.xml +++ b/.idea/sqldialects.xml @@ -7,6 +7,5 @@ - \ No newline at end of file diff --git a/src/Socialbox/Abstracts/Method.php b/src/Socialbox/Abstracts/Method.php index 3dbb855..d3f5971 100644 --- a/src/Socialbox/Abstracts/Method.php +++ b/src/Socialbox/Abstracts/Method.php @@ -8,8 +8,8 @@ use Socialbox\Exceptions\StandardException; use Socialbox\Interfaces\SerializableInterface; use Socialbox\Managers\SessionManager; use Socialbox\Objects\ClientRequest; +use Socialbox\Objects\Database\SessionRecord; use Socialbox\Objects\RpcRequest; -use Socialbox\Objects\SessionRecord; abstract class Method { diff --git a/src/Socialbox/Classes/Cryptography.php b/src/Socialbox/Classes/Cryptography.php index 20d242f..5de4846 100644 --- a/src/Socialbox/Classes/Cryptography.php +++ b/src/Socialbox/Classes/Cryptography.php @@ -108,14 +108,28 @@ class Cryptography */ public static function verifyContent(string $content, string $signature, string $publicKey): bool { - $publicKey = openssl_pkey_get_public(self::derToPem(Utilities::base64decode($publicKey), self::PEM_PUBLIC_HEADER)); - + try + { + $publicKey = openssl_pkey_get_public(self::derToPem(Utilities::base64decode($publicKey), self::PEM_PUBLIC_HEADER)); + } + catch(InvalidArgumentException $e) + { + throw new CryptographyException('Failed to decode public key: ' . $e->getMessage()); + } + if (!$publicKey) { throw new CryptographyException('Invalid public key: ' . openssl_error_string()); } - return openssl_verify($content, base64_decode($signature), $publicKey, self::HASH_ALGORITHM) === 1; + try + { + return openssl_verify($content, Utilities::base64decode($signature), $publicKey, self::HASH_ALGORITHM) === 1; + } + catch(InvalidArgumentException $e) + { + throw new CryptographyException('Failed to verify content: ' . $e->getMessage()); + } } /** diff --git a/src/Socialbox/Classes/RpcHandler.php b/src/Socialbox/Classes/RpcHandler.php index df24724..458a57c 100644 --- a/src/Socialbox/Classes/RpcHandler.php +++ b/src/Socialbox/Classes/RpcHandler.php @@ -2,10 +2,10 @@ namespace Socialbox\Classes; +use Exception; use InvalidArgumentException; use RuntimeException; use Socialbox\Enums\StandardHeaders; -use Socialbox\Exceptions\CryptographyException; use Socialbox\Exceptions\DatabaseOperationException; use Socialbox\Exceptions\RpcException; use Socialbox\Exceptions\StandardException; @@ -87,25 +87,31 @@ class RpcHandler try { $session = SessionManager::getSession($clientRequest->getSessionUuid()); - - // Verify the signature of the request - if(!Cryptography::verifyContent($clientRequest->getHash(), $clientRequest->getSignature(), $session->getPublicKey())) - { - throw new RpcException('Request signature check failed', 400); - } } catch(StandardException $e) { throw new RpcException($e->getMessage(), 400); } - catch(CryptographyException $e) - { - throw new RpcException('Request signature check failed (Cryptography Error)', 400, $e); - } catch(DatabaseOperationException $e) { throw new RpcException('Failed to verify session', 500, $e); } + + try + { + if(!Cryptography::verifyContent($clientRequest->getHash(), $clientRequest->getSignature(), $session->getPublicKey())) + { + throw new RpcException('Request signature check failed', 400); + } + } + catch(RpcException $e) + { + throw $e; + } + catch(Exception $e) + { + throw new RpcException('Request signature check failed (Cryptography Error): ' . $e->getMessage(), 400, $e); + } } return $clientRequest; diff --git a/src/Socialbox/Classes/StandardMethods/CreateSession.php b/src/Socialbox/Classes/StandardMethods/CreateSession.php index 9d9dcfe..9b11360 100644 --- a/src/Socialbox/Classes/StandardMethods/CreateSession.php +++ b/src/Socialbox/Classes/StandardMethods/CreateSession.php @@ -40,8 +40,6 @@ class CreateSession extends Method return $rpcRequest->produceError(StandardError::RPC_INVALID_ARGUMENTS, $e->getMessage()); } - return $rpcRequest->produceResponse([ - 'uuid' => $uuid - ]); + return $rpcRequest->produceResponse($uuid); } } \ No newline at end of file diff --git a/src/Socialbox/Classes/Utilities.php b/src/Socialbox/Classes/Utilities.php index 5f4b44b..a7c1fa2 100644 --- a/src/Socialbox/Classes/Utilities.php +++ b/src/Socialbox/Classes/Utilities.php @@ -43,7 +43,7 @@ class Utilities } catch(\JsonException $e) { - throw new \RuntimeException("Failed to encode json input", $e); + throw new InvalidArgumentException("Failed to encode json input", $e); } } diff --git a/src/Socialbox/Managers/SessionManager.php b/src/Socialbox/Managers/SessionManager.php index 4a9ab6b..d14d511 100644 --- a/src/Socialbox/Managers/SessionManager.php +++ b/src/Socialbox/Managers/SessionManager.php @@ -9,12 +9,11 @@ use PDOException; use Socialbox\Classes\Cryptography; use Socialbox\Classes\Database; - use Socialbox\Classes\Utilities; use Socialbox\Enums\SessionState; use Socialbox\Enums\StandardError; use Socialbox\Exceptions\DatabaseOperationException; use Socialbox\Exceptions\StandardException; - use Socialbox\Objects\SessionRecord; + use Socialbox\Objects\Database\SessionRecord; use Symfony\Component\Uid\Uuid; class SessionManager @@ -41,7 +40,6 @@ throw new InvalidArgumentException('The given public key is invalid', 400); } - $publicKey = Utilities::base64decode($publicKey); $uuid = Uuid::v4()->toRfc4122(); try diff --git a/src/Socialbox/Objects/SessionRecord.php b/src/Socialbox/Objects/Database/SessionRecord.php similarity index 98% rename from src/Socialbox/Objects/SessionRecord.php rename to src/Socialbox/Objects/Database/SessionRecord.php index 5b9ee23..19c1b6d 100644 --- a/src/Socialbox/Objects/SessionRecord.php +++ b/src/Socialbox/Objects/Database/SessionRecord.php @@ -1,6 +1,6 @@ produceError(StandardError::INTERNAL_SERVER_ERROR, Utilities::throwableToString($e)); diff --git a/tests/Socialbox/Classes/CryptographyTest.php b/tests/Socialbox/Classes/CryptographyTest.php index 483ba13..fa26a49 100644 --- a/tests/Socialbox/Classes/CryptographyTest.php +++ b/tests/Socialbox/Classes/CryptographyTest.php @@ -126,7 +126,7 @@ class CryptographyTest extends TestCase public function testEncryptFromFile() { - $file_path = __DIR__ . DIRECTORY_SEPARATOR . 'public.der'; + $file_path = __DIR__ . DIRECTORY_SEPARATOR . 'server_public.der'; $content = "Test Content"; $encryptedContent = Cryptography::encryptContent($content, file_get_contents($file_path)); @@ -139,8 +139,8 @@ class CryptographyTest extends TestCase public function testDecryptFromFile() { - $private_key_file = __DIR__ . DIRECTORY_SEPARATOR . 'private.der'; - $content = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'secret.txt'); + $private_key_file = __DIR__ . DIRECTORY_SEPARATOR . 'server_private.der'; + $content = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'server_secret.txt'); try { @@ -200,4 +200,20 @@ class CryptographyTest extends TestCase $this->assertFalse($result); } + public function testRequestSigning() + { + $client_private_der = __DIR__ . DIRECTORY_SEPARATOR . 'client_private.der'; + $client_public_der = __DIR__ . DIRECTORY_SEPARATOR . 'client_public.der'; + $content_file = __DIR__ . DIRECTORY_SEPARATOR . 'content.txt'; + + $hash = hash('sha1', file_get_contents($content_file)); + $this->assertEquals('fa2415f0735a8aa151195688852178e8fd6e77c5', $hash); + + $signature = Cryptography::signContent($hash, file_get_contents($client_private_der)); + $this->assertEquals("Gcnijq7V8AYXgdk/eP9IswXN7831FevlBNDTKN60Ku7xesPDuPX8e55+38WFGCQ87DbeiIr+61XIDoN4+bTM4Wl0YSUe7oHV9BBnBqGhyZTntDPedUYUomrF3IRcpVRK0SbQSRaYucIp/ZsSHdbQgQBtDCvH5pK1+5g+VK9ZFT16Isvk0PhMjZiLkUYxUklFuzak7agWiS3wllFPqYSM6ri0RF+5I5JbnR9fUAOfhOceax//5H7d2WsdLj6DwtuY+eL5WyHxSmGA04YeQF3JgOGJ3WX2DSH8L0zA7pkGOjz5y1Nu6+0U6KRUXcezU/iM4zy5OJOnD5eJH4pYZizkiA==", $signature); + + $result = Cryptography::verifyContent($hash, $signature, file_get_contents($client_public_der)); + $this->assertTrue($result); + } + } diff --git a/tests/Socialbox/Classes/client_private.der b/tests/Socialbox/Classes/client_private.der new file mode 100644 index 0000000..249edf1 --- /dev/null +++ b/tests/Socialbox/Classes/client_private.der @@ -0,0 +1 @@ +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDZb4K+28kKYe1CvHPWHJALJFS396HOFmBv+anpAVWMDGBUyAWbWEqxmTAV17cBHiICjDDCNFBpOZLWzIiUpdWKA0Jo+Vu9zgWSPUyGe/Lik4GFNZ38gfolfdKGnLNFnn4nFR/fsZQ7hg4wWDarJmhJ+ZSLShOz2uIb4LaKk2qy12c6Zepufgrbk9TwWZQiXkzqBWbrZDpw0pp50CzoIwEnYJ+a7vhb98jpeS+Jjnp5zWlFjv9RgzOQUOwwOK4We2gNAVeFC5BP9trklpTh1bJlit4CECH68fCGjgoTOU92UbgucgyA4O5FVPGQYPAMuiZMGFaqXE2E7z1XwYIMAL4VAgMBAAECggEAAKiJz3CYuO+gGnL+F7qjaSXCUE8VvPfoCwuNYHNEFXo9DJBmnL7EU2WrYG+wARCP7O7qd0dEidx9u36ytjyCcKT4nYni8lM1zU7rVvbnLbsuRZS/4RO/RaYfPxig94fDfSeJ2ma0i7G56onj+MBbyTZarZ7Bf8hpcmKg9pkNEcEVcklNIwwbXKBOGq75Vka/+W56JZKJD3G9YmfrAO5RGF1prh93MRXlxlN/91k/m2pqkN9xYofepn0ePmI8Ci18jrMpJbmeu8BkypzgvC/5EfHipn7y/yJ215o/EtB575muz2zngRXe+GVO5lB5d5PuEwmXoaV5o3BqkIcb3aiz4QKBgQD7P1AE2/3oATNUF1FwlXzvdCS7M2BB28jQWjzJvHus1d1+qA2StWPgCPG2D/YTtHPI3xefBnAmeSIFCFEub0YLONbRvtQAZdTt5SAaZuUyMprqD1sCUHCizyVO0wHxo3DS0sIFmo/Lpc+jnYHn3KcuRPRJk3ncZNCQhy9a/rrnxQKBgQDdjHY82YdkWQWj/xM1EuVtkVVeCJWJ6tSDn+Uq8d+hXILFAQ47GOUbzj4Ty4qGgsAgsaAGqja5t6CE+fYs8Q34FsxTsYgIRm0VXqtPm4aYTQ4PwKbmMPEOgEsXBywe5Y+QB0u/WuNyhgwgYP5cy1IS3HA1HmbTisi0zLEfkVWSEQKBgCuP36zoA88NHjwvStSNZrsR1SiMEN16YQgXDUEhKARglGXYd3n/b1Cx3E7n14+1Evo6DBtrf1h8WjSrK4A0lN1vPnfhcVqcTV3uAzHwsz6P3aJFhU8SaWUhK2POXCDsaKx1FGTqVpJFrom8zoBIFsiD9iMnqdJXvH3CoqhRUFDNAoGAEJdwU2ZHCXDRR1LW8WaU3/u+VOh3qnh3qdPTqb+ra74t3OsTUcGvhsGPTJQ1r5UjJk+nGFiu+IGT9+FwWjVDQo0SiEIHWfdMPAl28uNG1SkQIIXg+eQ4aUmaVgMnfrjaY4LoXVBFMFJxngslgXWIk/kGPjQkpzsBhOi/awnLSsECgYEAkSEb3CXfq1r/8qXMTzI+A9CGPr++aC2H6ytFNGJq4J+P40u1tcsfkwNGcQ0Hp+Qz3FHBYFuMxtjXDq0QSvVKEhdV9bjlZhTqN3lqWcCukU3ESqRbxsIj9izuncpxSP7G19WEU0anGD9ev+QWYdHPTBY9nn1+H0tkJjqh4XkRBuY= \ No newline at end of file diff --git a/tests/Socialbox/Classes/client_public.der b/tests/Socialbox/Classes/client_public.der new file mode 100644 index 0000000..58b132e --- /dev/null +++ b/tests/Socialbox/Classes/client_public.der @@ -0,0 +1 @@ +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2W+CvtvJCmHtQrxz1hyQCyRUt/ehzhZgb/mp6QFVjAxgVMgFm1hKsZkwFde3AR4iAowwwjRQaTmS1syIlKXVigNCaPlbvc4Fkj1Mhnvy4pOBhTWd/IH6JX3ShpyzRZ5+JxUf37GUO4YOMFg2qyZoSfmUi0oTs9riG+C2ipNqstdnOmXqbn4K25PU8FmUIl5M6gVm62Q6cNKaedAs6CMBJ2Cfmu74W/fI6XkviY56ec1pRY7/UYMzkFDsMDiuFntoDQFXhQuQT/ba5JaU4dWyZYreAhAh+vHwho4KEzlPdlG4LnIMgODuRVTxkGDwDLomTBhWqlxNhO89V8GCDAC+FQIDAQAB \ No newline at end of file diff --git a/tests/Socialbox/Classes/content.txt b/tests/Socialbox/Classes/content.txt new file mode 100644 index 0000000..f2afb1a --- /dev/null +++ b/tests/Socialbox/Classes/content.txt @@ -0,0 +1,4 @@ +{ + "method" : "ping", + "id" : "daa31852" +} \ No newline at end of file diff --git a/tests/Socialbox/Classes/private.der b/tests/Socialbox/Classes/server_private.der similarity index 100% rename from tests/Socialbox/Classes/private.der rename to tests/Socialbox/Classes/server_private.der diff --git a/tests/Socialbox/Classes/public.der b/tests/Socialbox/Classes/server_public.der similarity index 100% rename from tests/Socialbox/Classes/public.der rename to tests/Socialbox/Classes/server_public.der diff --git a/tests/Socialbox/Classes/secret.txt b/tests/Socialbox/Classes/server_secret.txt similarity index 100% rename from tests/Socialbox/Classes/secret.txt rename to tests/Socialbox/Classes/server_secret.txt diff --git a/tests/Socialbox/Managers/SessionManagerTest.php b/tests/Socialbox/Managers/SessionManagerTest.php index 1da708c..b376361 100644 --- a/tests/Socialbox/Managers/SessionManagerTest.php +++ b/tests/Socialbox/Managers/SessionManagerTest.php @@ -6,7 +6,7 @@ use InvalidArgumentException; use PHPUnit\Framework\TestCase; use Socialbox\Classes\Cryptography; use Socialbox\Classes\Utilities; -use Socialbox\Objects\SessionRecord; +use Socialbox\Objects\Database\SessionRecord; class SessionManagerTest extends TestCase {