Fix the login packet to contain both token and chain since v818 & update EncryptionUtils to reflect those changes.
Thanks to @Kaooot for giving me this information.
This removes the AuthPayload & CertificateChainPayload classes as their content is now included in the LoginPacket and SubClientLoginPacket.
This moves token validation into its own validation class named TokenValidationResult.
Users should now validate both when present and check whether the identity key in the chain and token matches.
This can be done using this logic:
- I skip checking whether token & certificate chain is set, as the vanilla client always sends both, but in real code this should be validated.
TokenValidationResult tokenValidationResult = EncryptionUtils.validateToken(packet.getAuthType(), packet.getToken());
ChainValidationResult chainValidationResult = EncryptionUtils.validateChain(packet.getAuthType(), packet.getCertificateChain());
IdentityClaims tokenClaims = tokenValidationResult.identityClaims();
IdentityClaims chainClaims = chainValidationResult.identityClaims();
if(!tokenClaims.identityPublicKey.equals(chainClaims.identityPublicKey)) {
throw new IllegalStateException("Token and chain public keys do not match!");
}
To support legacy versions, I also kept EncryptionUtils.validateChain method without the new AuthType parameter.
I also bumped the version to 3.0.0.Beta12-SNAPSHOT as this changes are breaking.
Previous one is better in my opinion, what does this PR aim to achieve?
public static HandshakeEntry processHandshake(BedrockSession session, LoginPacket packet, ProtocolVersion protocol, boolean strict) throws Exception {
ChainValidationResult result = EncryptionUtils.validatePayload(packet.getAuthPayload());
boolean xboxAuth = result.signed();
ChainValidationResult.IdentityClaims identityClaims = result.identityClaims();
ChainValidationResult.IdentityData identityData = identityClaims.extraData;
ECPublicKey identityPublicKey = (ECPublicKey) identityClaims.parsedIdentityPublicKey();
String xuid = identityData.xuid;
//UUID uuid = UUID.nameUUIDFromBytes(("pocket-auth-1-xuid:" + xuid).getBytes(StandardCharsets.UTF_8));
UUID uuid = identityData.identity;
SignedJWT clientDataJwt = SignedJWT.parse(packet.getClientJwt());
JsonObject clientData = HandshakeUtils.parseClientData(clientDataJwt, xuid, session);
if (!verifyJwt(clientDataJwt, identityPublicKey) && strict) {
xboxAuth = false;
}
String displayName;
if (ProxyServer.getInstance().getConfiguration().isReplaceUsernameSpaces()) {
displayName = identityData.displayName
.replaceAll(" ", "_");
} else {
displayName = identityData.displayName;
}
if (xboxAuth) {
ProxyConfig config = ProxyServer.getInstance().getConfiguration();
if (config.useLoginExtras()) {
clientData.addProperty("Waterdog_Auth", true);
}
}
return new HandshakeEntry(identityPublicKey, clientData, xuid, uuid, displayName, xboxAuth, protocol,
packet.getAuthPayload() instanceof CertificateChainPayload);
}
This is how WDPE handles both payloads. EncryptionUtils provides a clean API. Why split them?
what does this PR aim to achieve
It tries to allow for vanilla client replications, where the client is required to send both payloads (the certificate chain and the token). Which the vanilla client also does.
This is required for MITM Proxies where the server validates the login packet the way the vanilla client sends it. This behavior currently can not be replicated using this library.
Previous one is better in my opinion
And that is a valid point. Its easier to just validate one payload instead of both and then having to check whether both are even from the same person (eg the same identityPublicKey).
I need to have the ability to send both the Token payload and Certificate Chain, so that vanilla behavior can be replicated.
And I know that this pull request isnt perfect and I dont want to say that, but its currently the only way I get my job done.
If it would be perfect, it would revert the breaking changes made in 1febf69 (renaming fields), and just add those 2 new fields (authType & token) to the LoginPacket.
It tries to allow for vanilla client replications, where the client is required to send both payloads (the certificate chain and the token). Which the vanilla client also does.
Client is not required to send both of them, I'm sure that is a temporary thing. They will probably eventually phase Certificate payload out. There isn't a point of sending the same data twice in different formats.
BDS will should work fine with either of them. There should not be a need to send both of these. PMMP for some reason always expect to see Certificate for SELF_SIGNED but thats not also vanilla behavior, BDS works fine with either of them.
SupremeMortal had implemented the new system, I'm sure he knows his stuff. If both was required then he would have made it so it works with both.
If sending both is required then you should make it so the LoginPacket has two AuthPayload variables and keep the rest same. I think it would be simpler like that.