Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v0.1.2 #3

Merged
merged 2 commits into from
Jun 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public Optional<Response> handle(String domain, String path, IHTTPSession sessio
try {
response = mojangClient.hasJoinedServer(params.get("username"), params.get("serverId"), params.get("ip"));
} catch (UncheckedIOException e) {
log(ERROR, "An error occurred while verifying username [ " + params.get("username") + " ]:\n" +
log(ERROR, "An error occurred while verifying username [ " + params.get("username") + " ] at Mojang Yggdrasil server:\n" +
e.getCause());
}
if (response.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Haowei Wen <[email protected]> and contributors
* Copyright (C) 2022 Haowei Wen <[email protected]> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand All @@ -16,11 +16,18 @@
*/
package xyz.zuoyx.multiyggdrasil.transform.support;

import static xyz.zuoyx.multiyggdrasil.util.Logging.Level.DEBUG;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ASM9;
import static org.objectweb.asm.Opcodes.H_INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.IRETURN;
import java.lang.invoke.MethodHandle;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
Expand All @@ -31,6 +38,8 @@
import xyz.zuoyx.multiyggdrasil.transform.CallbackSupport;
import xyz.zuoyx.multiyggdrasil.transform.TransformContext;
import xyz.zuoyx.multiyggdrasil.transform.TransformUnit;
import xyz.zuoyx.multiyggdrasil.util.Logging;
import xyz.zuoyx.multiyggdrasil.util.Logging.Level;

public class YggdrasilKeyTransformUnit implements TransformUnit {

Expand All @@ -49,6 +58,35 @@ public static boolean verifyPropertySignature(Object property, PublicKey mojangK
return false;
}

@CallbackMethod
public static boolean verifyPropertySignatureNew(Signature mojangSignatureObj, String propertyValue, String base64Signature) {
byte[] sig = Base64.getDecoder().decode(base64Signature);
byte[] data = propertyValue.getBytes();

try {
mojangSignatureObj.update(data);
if (mojangSignatureObj.verify(sig))
return true;
} catch (SignatureException e) {
Logging.log(DEBUG, "Failed to verify signature with Mojang's key", e);
}

for (PublicKey customKey : PUBLIC_KEYS) {
try {
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initVerify(customKey);
signature.update(data);
if (signature.verify(sig))
return true;
} catch (GeneralSecurityException e) {
Logging.log(DEBUG, "Failed to verify signature with custom key " + customKey, e);
}
}

Logging.log(Level.WARNING, "Failed to verify property signature");
return false;
}

@Override
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) {
if ("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService".equals(className)) {
Expand All @@ -73,6 +111,32 @@ public void visitMethodInsn(int opcode, String owner, String name, String descri
}

});
} else if ("com.mojang.authlib.yggdrasil.YggdrasilServicesKeyInfo".equals(className)) {
return Optional.of(new ClassVisitor(ASM9, writer) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if ("validateProperty".equals(name) && "(Lcom/mojang/authlib/properties/Property;)Z".equals(desc)) {
ctx.markModified();

MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, "com/mojang/authlib/yggdrasil/YggdrasilServicesKeyInfo", "signature", "()Ljava/security/Signature;", false);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, "com/mojang/authlib/properties/Property", "getValue", "()Ljava/lang/String;", false);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, "com/mojang/authlib/properties/Property", "getSignature", "()Ljava/lang/String;", false);
CallbackSupport.invoke(ctx, mv, YggdrasilKeyTransformUnit.class, "verifyPropertySignatureNew");
mv.visitInsn(IRETURN);
mv.visitMaxs(-1, -1);
mv.visitEnd();

return null;
} else {
return super.visitMethod(access, name, desc, signature, exceptions);
}
}
});
} else {
return Optional.empty();
}
Expand Down