From 95dd4eb5f268a02fa465caed6b50186696d84c5a Mon Sep 17 00:00:00 2001 From: netkas Date: Sat, 8 Feb 2025 00:33:19 -0500 Subject: [PATCH] updated VerifyPeerSignature to make timed signatures optional, updated parameter names and improved validation --- .../Core/VerifyPeerSignature.php | 59 ++++++++------ src/Socialbox/Socialbox.php | 76 ++++++++++++++++++- 2 files changed, 110 insertions(+), 25 deletions(-) diff --git a/src/Socialbox/Classes/StandardMethods/Core/VerifyPeerSignature.php b/src/Socialbox/Classes/StandardMethods/Core/VerifyPeerSignature.php index 0d7f079..d78c79b 100644 --- a/src/Socialbox/Classes/StandardMethods/Core/VerifyPeerSignature.php +++ b/src/Socialbox/Classes/StandardMethods/Core/VerifyPeerSignature.php @@ -2,13 +2,12 @@ namespace Socialbox\Classes\StandardMethods\Core; - use Exception; use InvalidArgumentException; use Socialbox\Abstracts\Method; - use Socialbox\Enums\StandardError; + use Socialbox\Classes\Cryptography; + use Socialbox\Classes\Validator; use Socialbox\Exceptions\Standard\InvalidRpcArgumentException; use Socialbox\Exceptions\Standard\MissingRpcArgumentException; - use Socialbox\Exceptions\Standard\StandardRpcException; use Socialbox\Interfaces\SerializableInterface; use Socialbox\Objects\ClientRequest; use Socialbox\Objects\PeerAddress; @@ -24,19 +23,23 @@ public static function execute(ClientRequest $request, RpcRequest $rpcRequest): ?SerializableInterface { // Check if the required 'peer' parameter is set. - if(!$rpcRequest->containsParameter('signing_peer')) + if(!$rpcRequest->containsParameter('peer')) { - throw new MissingRpcArgumentException('signing_peer'); + throw new MissingRpcArgumentException('peer'); } if(!$rpcRequest->containsParameter('signature_uuid')) { throw new MissingRpcArgumentException('signature_uuid'); } - - if(!$rpcRequest->containsParameter('signature_key')) + elseif(!Validator::validateUuid($rpcRequest->getParameter('signature_uuid'))) { - throw new MissingRpcArgumentException('signature_key'); + throw new InvalidRpcArgumentException('signature_uuid', 'Invalid UUID V4'); + } + + if(!$rpcRequest->containsParameter('signature_public_key')) + { + throw new MissingRpcArgumentException('signature_public_key'); } if(!$rpcRequest->containsParameter('signature')) @@ -44,40 +47,48 @@ throw new MissingRpcArgumentException('signature'); } - if(!$rpcRequest->containsParameter('message_hash')) + if(!$rpcRequest->containsParameter('sha512')) { - throw new MissingRpcArgumentException('message_hash'); + throw new MissingRpcArgumentException('sha512'); } - - if(!$rpcRequest->containsParameter('signature_time')) + elseif(!Cryptography::validateSha512($rpcRequest->getParameter('sha512'))) { - throw new MissingRpcArgumentException('signature_time'); + throw new InvalidRpcArgumentException('sha512', 'Invalid SHA512'); } // Parse the peer address try { - $peerAddress = PeerAddress::fromAddress($rpcRequest->getParameter('signing_peer')); + $peerAddress = PeerAddress::fromAddress($rpcRequest->getParameter('peer')); } catch(InvalidArgumentException $e) { - throw new InvalidRpcArgumentException('signing_peer', $e); + throw new InvalidRpcArgumentException('peer', $e); } - try + if($rpcRequest->containsParameter('signature_time')) { - return $rpcRequest->produceResponse(Socialbox::verifyPeerSignature( + if(!is_numeric($rpcRequest->getParameter('signature_time'))) + { + throw new InvalidRpcArgumentException('signature_time', 'Invalid timestamp, must be a Unix Timestamp'); + } + + return $rpcRequest->produceResponse(Socialbox::verifyTimedSignature( signingPeer: $peerAddress, signatureUuid: $rpcRequest->getParameter('signature_uuid'), - signatureKey: $rpcRequest->getParameter('signature_key'), + signatureKey: $rpcRequest->getParameter('signature_public_key'), signature: $rpcRequest->getParameter('signature'), - messageHash: $rpcRequest->getParameter('message_hash'), - signatureTime: $rpcRequest->getParameter('signature_time') + messageHash: $rpcRequest->getParameter('sha512'), + signatureTime: (int)$rpcRequest->getParameter('signature_time') )->value); } - catch (Exception $e) - { - throw new StandardRpcException('Failed to resolve peer signature', StandardError::INTERNAL_SERVER_ERROR, $e); - } + + return $rpcRequest->produceResponse(Socialbox::verifySignature( + signingPeer: $peerAddress, + signatureUuid: $rpcRequest->getParameter('signature_uuid'), + signatureKey: $rpcRequest->getParameter('signature_public_key'), + signature: $rpcRequest->getParameter('signature'), + messageHash: $rpcRequest->getParameter('sha512'), + )->value); } } \ No newline at end of file diff --git a/src/Socialbox/Socialbox.php b/src/Socialbox/Socialbox.php index a734458..d47f1b3 100644 --- a/src/Socialbox/Socialbox.php +++ b/src/Socialbox/Socialbox.php @@ -764,7 +764,7 @@ * @param int $signatureTime The time at which the message was signed * @return SignatureVerificationStatus The status of the signature verification */ - public static function verifyPeerSignature(PeerAddress|string $signingPeer, string $signatureUuid, string $signatureKey, string $signature, string $messageHash, int $signatureTime): SignatureVerificationStatus + public static function verifyTimedSignature(PeerAddress|string $signingPeer, string $signatureUuid, string $signatureKey, string $signature, string $messageHash, int $signatureTime): SignatureVerificationStatus { try { @@ -824,6 +824,80 @@ return SignatureVerificationStatus::VERIFIED; } + /** + * Verifies the signature of a message using the public key of the signing peer both locally and externally. + * If the peer is registered locally, the signature is verified using the local public key. + * If the peer is external, the signature is verified by resolving the peer's public key from the external server. + * The signature is verified against the resolved public key, and the status of the verification is returned. + * + * @param PeerAddress|string $signingPeer The peer address or string identifier of the signing peer + * @param string $signatureUuid The UUID of the signature key to be resolved + * @param string $signatureKey The public key of the signature that was used to sign the message + * @param string $signature The signature to be verified + * @param string $messageHash The SHA-512 hash of the message that was signed + * @return SignatureVerificationStatus The status of the signature verification + */ + public static function verifySignature(PeerAddress|string $signingPeer, string $signatureUuid, string $signatureKey, string $signature, string $messageHash): SignatureVerificationStatus + { + try + { + if (!Cryptography::verifyMessage($messageHash, $signature, $signatureKey, false)) + { + return SignatureVerificationStatus::INVALID; + } + } + catch (CryptographyException) + { + return SignatureVerificationStatus::INVALID; + } + + // Resolve the peer signature key + try + { + $signingKey = self::resolvePeerSignature($signingPeer, $signatureUuid); + } + catch(StandardRpcException) + { + return SignatureVerificationStatus::UNVERIFIED; + } + + if($signingKey === null) + { + return SignatureVerificationStatus::UNVERIFIED; + } + + if($signingKey->getPublicKey() !== $signatureKey) + { + return SignatureVerificationStatus::PUBLIC_KEY_MISMATCH; + } + + if($signingKey->getUuid() !== $signatureUuid) + { + return SignatureVerificationStatus::UUID_MISMATCH; + } + + if(time() > $signingKey->getExpires()) + { + return SignatureVerificationStatus::EXPIRED; + } + + // Verify the signature with the resolved key + try + { + if (!Cryptography::verifyTimedMessage($messageHash, $signature, $signingKey->getPublicKey(), false)) + { + return SignatureVerificationStatus::INVALID; + } + } + catch (CryptographyException) + { + return SignatureVerificationStatus::INVALID; + } + + return SignatureVerificationStatus::VERIFIED; + } + + /** * Resolves a peer signature key based on the given peer address or string identifier. *