Document SignatureValidator

This commit is contained in:
Noel Németh 2022-06-11 03:05:16 +02:00
parent b0e0da0dd3
commit 24c3fbf4f3

View File

@ -3,6 +3,7 @@ package net.minestom.server.crypto;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.play.ClientCommandChatPacket;
import net.minestom.server.utils.crypto.KeyUtils;
import org.jetbrains.annotations.Nullable;
@ -13,12 +14,31 @@ import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.UUID;
/**
* General purpose functional interface to verify signatures.<br>
* Built in validators:
* <ul>
* <li>{@link SignatureValidator#PASS}: will always report true</li>
* <li>{@link SignatureValidator#FAIL}: will always report false</li>
* <li>{@link SignatureValidator#YGGDRASIL}: Uses SHA1 with RSA and Yggdrasil Public Key for
* verifying signatures</li>
* <li>{@link SignatureValidator#from(Player)}: Uses SHA256 with RSA and the
* Player's {@link PlayerPublicKey#publicKey()}</li>
* <li>{@link SignatureValidator#from(PublicKey, KeyUtils.SignatureAlgorithm)}: General purpose factory method</li>
* </ul>
*/
@FunctionalInterface
public interface SignatureValidator {
SignatureValidator PASS = (payload, signature) -> true;
SignatureValidator FAIL = (payload, signature) -> false;
SignatureValidator YGGDRASIL = createYggdrasilValidator();
/**
* Validate signature. This should not throw any exception instead it should
* return false.
*
* @return true only if the signature is valid
*/
boolean validate(byte[] payload, byte[] signature);
static SignatureValidator from(PublicKey publicKey, KeyUtils.SignatureAlgorithm algorithm) {
@ -35,6 +55,19 @@ public interface SignatureValidator {
});
}
/**
* Can be used to verify signatures of {@link net.minestom.server.network.packet.client.play.ClientChatMessagePacket}
* and {@link ClientCommandChatPacket#signatures()}. For command args the signature is generated for the given
* value wrapped in {@link Component#text(String)} or for the preview if it's present regardless of the arg node
* name. Vanilla implementation of argument signing can be found at (Mojang mappings):
* <i>net.minecraft.client.player.LocalPlayer#signCommandArguments</i><br>
*
* @param validator validator acquired from {@link SignatureValidator#from(Player)}
* @param signer uuid of the player who signed this component
* @param signature signature data
* @param component the component that was signed
* @return true if the signature is valid
*/
static boolean validate(SignatureValidator validator, UUID signer, MessageSignature signature, Component component) {
final byte[] componentBytes = GsonComponentSerializer.gson().serialize(component).getBytes(StandardCharsets.UTF_8);
byte[] signerDetails = new byte[32+ componentBytes.length];
@ -46,6 +79,12 @@ public interface SignatureValidator {
return validator.validate(bytebuffer.array(), signature.signature());
}
/**
* Creates a validator from the player's public key using SHA256 with RSA
*
* @param player source of the key
* @return null if the player didn't send a public key
*/
static @Nullable SignatureValidator from(Player player) {
if (player.getPlayerConnection().getPlayerPublicKey() == null) return null;
return from(player.getPlayerConnection().getPlayerPublicKey().publicKey(), KeyUtils.SignatureAlgorithm.SHA256withRSA);