Throw a more specific exception for JWT handling errors

This commit is contained in:
Dylan K. Taylor 2020-05-13 21:23:04 +01:00
parent 486e0e710b
commit 84291e7980
4 changed files with 43 additions and 13 deletions

View File

@ -0,0 +1,28 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe;
final class JwtException extends \RuntimeException{
}

View File

@ -64,38 +64,38 @@ final class JwtUtils{
* @return mixed[]
* @phpstan-return array{mixed[], mixed[], string}
*
* @throws \UnexpectedValueException
* @throws JwtException
*/
public static function parse(string $token) : array{
$v = explode(".", $token);
if(count($v) !== 3){
throw new \UnexpectedValueException("Expected exactly 3 JWT parts, got " . count($v));
throw new JwtException("Expected exactly 3 JWT parts, got " . count($v));
}
$header = json_decode(self::b64UrlDecode($v[0]), true);
if(!is_array($header)){
throw new \UnexpectedValueException("Failed to decode JWT header JSON: " . json_last_error_msg());
throw new JwtException("Failed to decode JWT header JSON: " . json_last_error_msg());
}
$body = json_decode(self::b64UrlDecode($v[1]), true);
if(!is_array($body)){
throw new \UnexpectedValueException("Failed to decode JWT payload JSON: " . json_last_error_msg());
throw new JwtException("Failed to decode JWT payload JSON: " . json_last_error_msg());
}
$signature = self::b64UrlDecode($v[2]);
return [$header, $body, $signature];
}
/**
* @throws \UnexpectedValueException
* @throws JwtException
*/
public static function verify(string $jwt, PublicKeyInterface $signingKey) : bool{
$parts = explode('.', $jwt);
if(count($parts) !== 3){
throw new \UnexpectedValueException("Expected exactly 3 JWT parts, got " . count($parts));
throw new JwtException("Expected exactly 3 JWT parts, got " . count($parts));
}
[$header, $body, $signature] = $parts;
$plainSignature = self::b64UrlDecode($signature);
if(strlen($plainSignature) !== 96){
throw new \UnexpectedValueException("JWT signature has unexpected length, expected 96, got " . strlen($plainSignature));
throw new JwtException("JWT signature has unexpected length, expected 96, got " . strlen($plainSignature));
}
[$rString, $sString] = str_split($plainSignature, 48);
@ -110,7 +110,7 @@ final class JwtUtils{
switch($v){
case 0: return false;
case 1: return true;
case -1: throw new \UnexpectedValueException("Error verifying JWT signature: " . openssl_error_string());
case -1: throw new JwtException("Error verifying JWT signature: " . openssl_error_string());
default: throw new AssumptionFailedError("openssl_verify() should only return -1, 0 or 1");
}
}
@ -144,7 +144,7 @@ final class JwtUtils{
}
$decoded = base64_decode(strtr($str, '-_', '+/'), true);
if($decoded === false){
throw new \UnexpectedValueException("Malformed base64url encoded payload could not be decoded");
throw new JwtException("Malformed base64url encoded payload could not be decoded");
}
return $decoded;
}

View File

@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\auth;
use FG\ASN1\Exception\ParserException;
use Mdanter\Ecc\Crypto\Key\PublicKeyInterface;
use Mdanter\Ecc\Serializer\PublicKey\DerPublicKeySerializer;
use pocketmine\network\mcpe\JwtException;
use pocketmine\network\mcpe\JwtUtils;
use pocketmine\network\mcpe\protocol\LoginPacket;
use pocketmine\scheduler\AsyncTask;
@ -106,7 +107,7 @@ class ProcessLoginTask extends AsyncTask{
private function validateToken(string $jwt, ?string &$currentPublicKey, bool $first = false) : void{
try{
[$headers, $claims, ] = JwtUtils::parse($jwt);
}catch(\UnexpectedValueException $e){
}catch(JwtException $e){
throw new VerifyLoginException("Failed to parse JWT: " . $e->getMessage(), 0, $e);
}
@ -134,7 +135,7 @@ class ProcessLoginTask extends AsyncTask{
if(!JwtUtils::verify($jwt, $signingKey)){
throw new VerifyLoginException("%pocketmine.disconnect.invalidSession.badSignature");
}
}catch(\UnexpectedValueException $e){
}catch(JwtException $e){
throw new VerifyLoginException($e->getMessage(), 0, $e);
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\JwtException;
use pocketmine\network\mcpe\JwtUtils;
use pocketmine\network\mcpe\protocol\serializer\NetworkBinaryStream;
use pocketmine\network\mcpe\protocol\types\login\AuthenticationData;
@ -89,7 +90,7 @@ class LoginPacket extends DataPacket implements ServerboundPacket{
//validate every chain element
try{
[, $claims, ] = JwtUtils::parse($chain);
}catch(\UnexpectedValueException $e){
}catch(JwtException $e){
throw new PacketDecodeException($e->getMessage(), 0, $e);
}
if(isset($claims["extraData"])){
@ -118,7 +119,7 @@ class LoginPacket extends DataPacket implements ServerboundPacket{
$this->clientDataJwt = $buffer->get($buffer->getLInt());
try{
[, $clientData, ] = JwtUtils::parse($this->clientDataJwt);
}catch(\UnexpectedValueException $e){
}catch(JwtException $e){
throw new PacketDecodeException($e->getMessage(), 0, $e);
}